Как разделить дерево в расте
Перейти к содержимому

Как разделить дерево в расте

  • автор:

Чем выдалбливать деревянные двери в Раст

Рейдерство в Раст может быть очень трудоемким и времязатратным процессом, особенно если делать это подручными средствами по типу деревянного копья. Но какой инструмент для выдалбливания дверей покажет себя лучше всего, если под рукой нет взрывчатки? Давайте разбираться вместе! Мы будем моделировать ситуацию, когда вы на старте вайпа решили попытать удачу на небольшом домике с одной дверью к ящику. У вас нет разрывных патронов и нормальной винтовки, а лишь первый верстак, большое количество времени, и желание обогатится.

Чем лучше всего выдалбливать деревянные двери

Чем выдалбливать деревянные двери в Раст

Для любого рейда нам потребуются ресурсы, проще всего использовать копье, так как деревья практически всегда под рукой, но такой процесс займет больше времени. К слову, вам потребуется целых 95 копьев (28 500 дерева ) и более 40 минут времени, так что это не самый лучший способ, поэтому рассмотрим более рентабельные предметы для рейда.

Важно упомянуть, что последующее предметы можно скрафтить лишь при помощи верстака первого уровня , а также изучив чертеж перед этим, что обойдется в 75 скрапа .

Чем выдалбливать деревянные двери в Раст

Первый на очереди самодельный меч . Чтобы разбить деревянную дверь, потребует примерно 11. Для его изготовления потребуется 15 металлических фрагментов и одно металлическое лезвие

Чем выдалбливать деревянные двери в Раст

Второй на очереди топорик , который имеет смысл использовать когда он у вас уже изучен или у вас нет желания искать лезвия, так как ресурсов для его крафта нужно больше, а именно 75 металлических фрагментов и 100 дерева . Чтобы сломать дверь, также потребуется их также потребуется 11 штук.

Чем выдалбливать деревянные двери в Раст

Последний из вариантов пожалуй самый быстрый, но и самый опасный, так как рейд самодельным пистолетом вызывает много шума, что заставит появиться нежданных гостей. Для его изготовления не нужно ничего изучать, просто имейте при себе 75 дерева и 30 металлических фрагментов . Лучше всего брать на рейд 2 пистолета, ведь часто он очень долго стреляет и перезаряжается, поэтому в случае когда вам будут мешать, у вас есть теоретический шанс достать другой самодельный пистолет и выстрелить в обидчика.

Для полного комплекта вам также необходимы самодельные патроны в количестве 50 штук. Один патрон обойдется в 5 камня и 5 пороха . Патроны и ресурсы для них изготавливаются на первом верстаке .

Конечно, помимо самодельного пистолета вы можете использовать и другое оружие которе использует самодельный патрон. К примеру самодельный дробовик или двухствольный дробовик, но его нужно еще купить и изучить.

Чем выдалбливать деревянные двери в Раст

По времени такой рейд займет примерно +- 20 минут в зависимости от различных обстоятельств.

photo - Вадим Белинский

Вадим Белинский

Главный редактор сайта

Киберспорт не оставил шансов юриспруденции и финансам в выборе основного занятия. Знаю про CS:GO практически все и немного больше. За десятилетний опыт игры, данная киберспортивная дисциплина открылась по новому, о чем вы узнаете в моих статьях.

Язык программирования Rust

До сих пор все примеры в этой главе определяли несколько модулей в одном файле. Когда модули становятся большими, вы можете захотеть переместить их определения в отдельные файлы, чтобы упростить навигацию по коду.

Например, давайте начнём с кода из листинга 7-17, в котором было несколько модулей ресторана. Мы будем извлекать модули в файлы вместо того, чтобы определять все модули в корневом модуле крейта. В нашем случае корневой модуль крейта — src/lib.rs, но это разделение также работает и с бинарными крейтами, у которых корневой модуль крейта — src/main.rs.

Сначала мы извлечём модуль front_of_house в свой собственный файл. Удалите код внутри фигурных скобок для модуля front_of_house , оставив только объявление mod front_of_house; , так что теперь src/lib.rs содержит код, показанный в листинге 7-21. Обратите внимание, что этот вариант не скомпилируется, пока мы не создадим файл src/front_of_house.rs из листинге 7-22.

mod front_of_house; pub use crate::front_of_house::hosting; pub fn eat_at_restaurant()

Листинг 7-21. Объявление модуля front_of_house , чьё содержимое будет в src/front_of_house.rs

Затем поместим код, который был в фигурных скобках, в новый файл с именем src/front_of_house.rs, как показано в листинге 7-22. Компилятор знает, что нужно искать в этом файле, потому что он наткнулся в корневом модуле крейта на объявление модуля с именем front_of_house .

pub mod hosting < pub fn add_to_waitlist() <>> 

Листинг 7-22. Определение содержимого модуля front_of_house в файле src/front_of_house.rs

Обратите внимание, что вам нужно только один раз загрузить файл с помощью объявления mod в вашем дереве модулей. Как только компилятор узнает, что файл является частью проекта (и узнает, где в дереве модулей находится код из-за того, куда вы поместили инструкцию mod ), другие файлы в вашем проекте должны ссылаться на код загруженного файла, используя путь к месту, где он был объявлен, как описано в разделе «Пути для ссылки на элемент в дереве модулей» . Другими словами, mod — это не операция «включения», которую вы могли видеть в других языках программирования.

Далее мы извлечём модуль hosting в его собственный файл. Процесс немного отличается, потому что hosting является дочерним модулем для front_of_house , а не корневого модуля. Мы поместим файл для hosting в новый каталог, который будет назван по имени его предка в дереве модулей, в данном случае это src/front_of_house/.

Чтобы начать перенос hosting , мы меняем src/front_of_house.rs так, чтобы он содержал только объявление модуля hosting :

pub mod hosting; 

Затем мы создаём каталог src/front_of_house и файл hosting.rs, в котором будут определения, сделанные в модуле hosting :

pub fn add_to_waitlist() <> 

Если вместо этого мы поместим hosting.rs в каталог src, компилятор будет думать, что код в hosting.rs это модуль hosting , объявленный в корне крейта, а не объявленный как дочерний модуль front_of_house . Правила компилятора для проверки какие файлы содержат код каких модулей предполагают, что каталоги и файлы точно соответствуют дереву модулей.

Альтернативные пути к файлам

  • src/front_of_house.rs (что мы рассматривали)
  • src/front_of_house/mod.rs (старый стиль, всё ещё поддерживаемый путь)
  • src/front_of_house/hosting.rs (что мы рассматривали)
  • src/front_of_house/hosting/mod.rs (старый стиль, всё ещё поддерживаемый путь)

Мы перенесли код каждого модуля в отдельный файл, а дерево модулей осталось прежним. Вызовы функций в eat_at_restaurant будут работать без каких-либо изменений, несмотря на то, что определения находятся в разных файлах. Этот метод позволяет перемещать модули в новые файлы по мере увеличения их размеров.

Обратите внимание, что инструкция pub use crate::front_of_house::hosting в src/lib.rs также не изменилась, и use не влияет на то, какие файлы компилируются как часть крейта. Ключевое слово mod объявляет модули, и Rust ищет в файле с тем же именем, что и у модуля, код, который входит в этот модуль.

Итог

Rust позволяет разбить пакет на несколько крейтов и крейт — на модули, так что вы можете ссылаться на элементы, определённые в одном модуле, из другого модуля. Это можно делать при помощи указания абсолютных или относительных путей. Эти пути можно добавить в область видимости инструкцией use , поэтому вы можете пользоваться более короткими путями для многократного использования элементов в этой области видимости. Код модуля по умолчанию является приватным, но можно сделать определения общедоступными, добавив ключевое слово pub .

В следующей главе мы рассмотрим некоторые коллекции структур данных из стандартной библиотеки, которые вы можете использовать в своём аккуратно организованном коде.

Разделение предметов в инвентаре

Обзор игры Rust

Привет всем Растоманам и Растоманкам! Я снова с вами, и со мной интересная мысль от сообщества — Разделение предметов в инвентаре. Идея такова, при клике правой кнопкой на кучке, например, дерева, появляется контекстное меню, а там #split. Кликаем по нему и… вот что видим:

Разделение предметов в инвентаре

Согласитесь, так весьма удобно? �� Будем ждать и надеяться на то, что разработчики во главе с Гарри заметят это предложение и внедрят нечто похожее в игру.

Благодарю за внимание, на этом пока всё. Пока. Всё.

Контейнеры и модули

Когда проект начинает разрастаться, то хорошей практикой разработки программного обеспечения считается: разбить его на небольшие кусочки, а затем собрать их вместе. Также важно иметь четко определенный интерфейс, так как часть вашей функциональности является приватной, а часть — публичной. Для облегчения такого рода вещей Rust обладает модульной системой.

Основные термины: контейнеры и модули

Rust имеет два различных термина, которые относятся к модульной системе: контейнер и модуль. Контейнер — это синоним библиотеки или пакета на других языках. Именно поэтому инструмент управления пакетами в Rust называется Cargo: вы пересылаете ваши контейнеры другим с помощью Cargo. Контейнеры могут производить исполняемый файл или библиотеку, в зависимости от проекта.

Каждый контейнер имеет неявный корневой модуль, содержащий код для этого контейнера. В рамках этого базового модуля можно определить дерево суб-модулей. Модули позволяют разделить ваш код внутри контейнера.

В качестве примера, давайте сделаем контейнер phrases, который выдает нам различные фразы на разных языках. Чтобы не усложнять пример, мы будем использовать два вида фраз: «greetings» и «farewells», и два языка для этих фраз: английский и японский (日本語). Мы будем использовать следующий шаблон модуля:

 +-----------+ +---| greetings | | +-----------+ +---------+ | +---| english |---+ | +---------+ | +-----------+ | +---| farewells | +---------+ | +-----------+ | phrases |---+ +---------+ | +-----------+ | +---| greetings | | +----------+ | +-----------+ +---| japanese |--+ +----------+ | | +-----------+ +---| farewells | +-----------+ 

В этом примере, phrases — это название нашего контейнера. Все остальное — модули. Вы можете видеть, что они образуют дерево, в основании которого располагается корень контейнера — phrases .

Теперь, когда у нас есть схема, давайте определим модули в коде. Для начала создайте новый контейнер с помощью Cargo:

$ cargo new phrases $ cd phrases 

Если вы помните, то эта команда создает простой проект:

$ tree . . ├── Cargo.toml └── src └── lib.rs 1 directory, 2 files 

src/lib.rs — корень нашего контейнера, соответствующий phrases в нашей диаграмме выше.

Объявление модулей

Для объявления каждого из наших модулей, мы используем ключевое слово mod . Давайте сделаем, чтобы наш src/lib.rs выглядел следующим образом:

mod english < mod greetings < >mod farewells < >> mod japanese < mod greetings < >mod farewells < >> 

После ключевого слова mod , вы задаете имя модуля. Имена модулей следуют соглашениям, как и другие идентификаторы Rust: lower_snake_case . Содержание каждого модуля обрамляется в фигурные скобки ( <> ).

Внутри mod вы можете объявить суб- mod . Мы можем обращаться к суб-модулям с помощью нотации ( :: ). Так выглядят обращения к нашим четырем вложенным модулям: english::greetings , english::farewells , japanese::greetings и japanese::farewells . Так как суб-модули располагаются в пространстве имен своих родительских модулей, то суб-модули english::greetings и japanese::greetings не конфликтуют, несмотря на то, что они имеют одинаковые имена, greetings .

Так как в этом контейнере нет функции main() , и называется он lib.rs , Cargo соберет этот контейнер в виде библиотеки:

$ cargo build Compiling phrases v0.0.1 (file:///home/you/projects/phrases) $ ls target/debug build deps examples libphrases-a7448e02a0468eaa.rlib native 

libphrase-hash.rlib — это скомпилированный контейнер. Прежде чем мы рассмотрим, как его можно использовать из другого контейнера, давайте разобьем его на несколько файлов.

Контейнеры с несколькими файлами

Если бы каждый контейнер мог состоять только из одного файла, тогда этот файл был бы очень большим. Зачастую легче разделить контейнер на несколько файлов, и Rust поддерживает это двумя способами.

Вместо объявления модуля наподобие:

mod english < // contents of our module go here >

Мы можем объявить наш модуль в виде:

mod english; 

Если мы это сделаем, то Rust будет ожидать, что найдет либо файл english.rs , либо файл english/mod.rs с содержимым нашего модуля.

Обратите внимание, что в этих файлах вам не требуется заново объявлять модуль: это уже сделано при изначальном объявлении mod .

С помощью этих двух приемов мы можем разбить наш контейнер на две директории и семь файлов:

$ tree . . ├── Cargo.lock ├── Cargo.toml ├── src │ ├── english │ │ ├── farewells.rs │ │ ├── greetings.rs │ │ └── mod.rs │ ├── japanese │ │ ├── farewells.rs │ │ ├── greetings.rs │ │ └── mod.rs │ └── lib.rs └── target └── debug ├── build ├── deps ├── examples ├── libphrases-a7448e02a0468eaa.rlib └── native 

src/lib.rs — корень нашего контейнера, и выглядит он следующим образом:

mod english; mod japanese; 

Эти два объявления информируют Rust, что следует искать: src/english.rs или src/english/mod.rs , src/japanese.rs или src/japanese/mod.rs , в зависимости от нашей структуры. В данном примере мы выбрали второй вариант из-за того, что наши модули содержат суб-модули. И src/english/mod.rs и src/japanese/mod.rs выглядят следующим образом:

mod greetings; mod farewells; 

В свою очередь, эти объявления информируют Rust, что следует искать: src/english/greetings.rs , src/japanese/greetings.rs , src/english/farewells.rs , src/japanese/farewells.rs или src/english/greetings/mod.rs , src/japanese/greetings/mod.rs , src/english/farewells/mod.rs , src/japanese/farewells/mod.rs . Так как эти суб-модули не содержат свои собственные суб-модули, то мы выбрали src/english/greetings.rs и src/japanese/farewells.rs . Вот так!

Содержание src/english/greetings.rs и src/japanese/farewells.rs являются пустыми на данный момент. Давайте добавим несколько функций.

Поместите следующий код в src/english/greetings.rs :

fn hello() -> String < "Hello!".to_string() > 

Следующий код в src/english/farewells.rs :

fn goodbye() -> String < "Goodbye.".to_string() > 

Следующий код в src/japanese/greetings.rs :

fn hello() -> String < "こんにちは".to_string() > 

Конечно, вы можете скопировать и вставить этот код с этой страницы, или просто напечатать что-нибудь еще. Вам совершенно не обязательно знать, что на японском языке написано «Konnichiwa», чтобы понять как работает модульная система.

Поместите следующий код в src/japanese/farewells.rs :

fn goodbye() -> String < "さようなら".to_string() > 

(Это «Sayonara», если вам интересно.)

Теперь у нас есть некоторая функциональность в нашем контейнере, давайте попробуем использовать его из другого контейнера.

Импорт внешних контейнеров

У нас есть библиотечный контейнер. Давайте создадим исполняемый контейнер, который импортирует и использует нашу библиотеку.

Создайте файл src/main.rs и положите в него следующее: (при этом он не будет компилироваться)

extern crate phrases; fn main() < println!("Hello in English: <>", phrases::english::greetings::hello()); println!("Goodbye in English: <>", phrases::english::farewells::goodbye()); println!("Hello in Japanese: <>", phrases::japanese::greetings::hello()); println!("Goodbye in Japanese: <>", phrases::japanese::farewells::goodbye()); > 

Объявление extern crate информирует Rust о том, что для компиляции и компоновки кода нам нужен контейнер phrases . После этого объявление мы можем использовать модули контейнера phrases . Как мы уже упоминали ранее, вы можете использовать два подряд идущих символа двоеточия для обращения к суб-модулям и функциям внутри них.

Кроме того, Cargo предполагает, что src/main.rs — это корень бинарного, а не библиотечного контейнера. Теперь наш пакет содержит два контейнера: src/lib.rs и src/main.rs . Этот шаблон является довольно распространенным для исполняемых контейнеров: основная функциональность сосредоточена в библиотечном контейнере, а исполняемый контейнер использует эту библиотеку. Таким образом, другие программы также могут использовать библиотечный контейнер, к тому же такой подход обеспечивает отделение интереса (разделение функциональности).

Хотя этот код все еще не работает. Мы получаем четыре ошибки, которые выглядят примерно так:

$ cargo build Compiling phrases v0.0.1 (file:///home/you/projects/phrases) src/main.rs:4:38: 4:72 error: function `hello` is private src/main.rs:4 println!("Hello in English: <>", phrases::english::greetings::hello()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ note: in expansion of format_args! :2:25: 2:58 note: expansion site :1:1: 2:62 note: in expansion of print! :3:1: 3:54 note: expansion site :1:1: 3:58 note: in expansion of println! phrases/src/main.rs:4:5: 4:76 note: expansion site 

По умолчанию все элементы в Rust являются приватными. Давайте поговорим об этом более подробно.

Экспорт публичных интерфейсов

Rust позволяет точно контролировать, какие элементы вашего интерфейса являются публичными, и поэтому по умолчанию все элементы являются приватными. Чтобы сделать элементы публичными, вы используете ключевое слово pub . Давайте сначала сосредоточимся на модуле english , для чего сократим файл src/main.rs до этого:

extern crate phrases; fn main() < println!("Hello in English: <>", phrases::english::greetings::hello()); println!("Goodbye in English: <>", phrases::english::farewells::goodbye()); > 

В файле src/lib.rs в объявлении модуля english давайте добавим модификатор pub :

pub mod english; mod japanese; 

В файле src/english/mod.rs давайте сделаем оба модуля с модификатором pub :

pub mod greetings; pub mod farewells; 

В файле src/english/greetings.rs давайте добавим модификатор pub к объявлению нашей функции fn :

pub fn hello() -> String

А также в файле src/english/farewells.rs :

pub fn goodbye() -> String

Теперь наши контейнеры компилируются, хотя и с предупреждениями о том, что функции в модуле japanese не используются:

$ cargo run Compiling phrases v0.0.1 (file:///home/you/projects/phrases) src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default src/japanese/greetings.rs:1 fn hello() -> String < src/japanese/greetings.rs:2 "こんにちは".to_string() src/japanese/greetings.rs:3 > src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default src/japanese/farewells.rs:1 fn goodbye() -> String < src/japanese/farewells.rs:2 "さようなら".to_string() src/japanese/farewells.rs:3 > Running `target/debug/phrases` Hello in English: Hello! Goodbye in English: Goodbye. 

Теперь, когда функции являются публичными, мы можем их использовать. Отлично! Тем не менее, написание phrases::english::greetings::hello() является очень длинным и неудобным. Rust предоставляет другое ключевое слово, для импорта имен в текущую область, чтобы для обращения можно было использовать короткие имена. Давайте поговорим об этом ключевом слове, use .

Импорт модулей с помощью use

Rust предоставляет ключевое слово use , которое позволяет импортировать имена в нашу локальную область видимости. Давайте изменим файл src/main.rs , чтобы он выглядел следующим образом:

extern crate phrases; use phrases::english::greetings; use phrases::english::farewells; fn main() < println!("Hello in English: <>", greetings::hello()); println!("Goodbye in English: <>", farewells::goodbye()); > 

Две строки, начинающиеся с use , импортируют соответствующие модули в локальную область видимости, поэтому мы можем обратиться к функциям по гораздо более коротким именам. По соглашению, при импорте функции, лучшей практикой считается импортировать модуль, а не функцию непосредственно. Другими словами, вы могли бы сделать следующее:

extern crate phrases; use phrases::english::greetings::hello; use phrases::english::farewells::goodbye; fn main() < println!("Hello in English: <>", hello()); println!("Goodbye in English: <>", goodbye()); > 

Но такой подход не является идиоматическим. Он значительно чаще приводит к конфликту имен. Для нашей короткой программы это не так важно, но, как только программа разрастается, это становится проблемой. Если у нас возникает конфликт имен, то Rust выдает ошибку компиляции. Например, если мы сделаем функции japanese публичными, и пытаемся скомпилировать этот код:

extern crate phrases; use phrases::english::greetings::hello; use phrases::japanese::greetings::hello; fn main() < println!("Hello in English: <>", hello()); println!("Hello in Japanese: <>", hello()); > 

Rust выдаст нам сообщение об ошибке во время компиляции:

 Compiling phrases v0.0.1 (file:///home/you/projects/phrases) src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252] src/main.rs:4 use phrases::japanese::greetings::hello; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error Could not compile `phrases`. 

Если мы импортируем несколько имен из одного модуля, то нам совсем не обязательно писать одно и то же много раз. Вместо этого кода:

use phrases::english::greetings; use phrases::english::farewells; 

Вы можете использовать сокращение:

use phrases::english::; 

Реэкспорт с помощью pub use

Вы можете использовать use не просто для сокращения идентификаторов. Вы также можете использовать его внутри вашего контейнера, чтобы реэкспортировать функцию из другого модуля. Это позволяет представить внешний интерфейс, который может не напрямую отображать внутреннюю организацию кода.

Давайте посмотрим на примере. Измените файл src/main.rs следующим образом:

extern crate phrases; use phrases::english::; use phrases::japanese; fn main() < println!("Hello in English: <>", greetings::hello()); println!("Goodbye in English: <>", farewells::goodbye()); println!("Hello in Japanese: <>", japanese::hello()); println!("Goodbye in Japanese: <>", japanese::goodbye()); > 

Затем измените файл src/lib.rs , чтобы сделать модуль japanese с публичным:

pub mod english; pub mod japanese; 

Далее, убедитесь, что обе функции публичные, сперва в src/japanese/greetings.rs :

pub fn hello() -> String

А затем в src/japanese/farewells.rs :

pub fn goodbye() -> String

Наконец, измените файл src/japanese/mod.rs вот так:

pub use self::greetings::hello; pub use self::farewells::goodbye; mod greetings; mod farewells; 

Объявление pub use привносит указанную функцию в эту часть области видимости нашей модульной иерархии. Так как мы использовали pub use внутри нашего модуля japanese , то теперь мы можем вызывать функцию phrases::japanese::hello() и функцию phrases::japanese::goodbye() , хотя код для них расположен в phrases::japanese::greetings::hello() и phrases::japanese::farewells::goodbye() соответственно. Наша внутренняя организация не определяет наш внешний интерфейс.

В этом примере мы используем pub use отдельно для каждой функции, которую хотим привнести в область japanese . В качестве альтернативы, мы могли бы использовать шаблонный синтаксис, чтобы включать в себя все элементы из модуля greetings в текущую область: pub use self::greetings::* .

Что можно сказать о self ? По умолчанию объявления use используют абсолютные пути, начинающиеся с корня контейнера. self , напротив, формирует эти пути относительно текущего места в иерархии. У use есть еще одна особая форма: вы можете использовать use super:: , чтобы подняться по дереву на один уровень вверх от вашего текущего местоположения. Некоторые предпочитают думать о self как о . , а о super как о .. , что для многих командных оболочек является представлением для текущей директории и для родительской директории соответственно.

Вне use , пути относительны: foo::bar() ссылаться на функцию внутри foo относительно того, где мы находимся. Если же используется префикс :: , то ::foo::bar() будет ссылаться на другой foo , абсолютный путь относительно корня контейнера.

Кроме того, обратите внимание, что мы использовали pub use прежде, чем объявили наши модули с помощью mod . Rust требует, чтобы объявления use шли в первую очередь.

Следующий код собирается и работает:

$ cargo run Compiling phrases v0.0.1 (file:///home/you/projects/phrases) Running `target/debug/phrases` Hello in English: Hello! Goodbye in English: Goodbye. Hello in Japanese: こんにちは Goodbye in Japanese: さようなら 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *