각각 자체 파일에 여러 구조체가있는 모듈을 갖고 싶습니다 . 사용하여 A Math
예로서 모듈 :
Math/
Vector.rs
Matrix.rs
Complex.rs
각 구조체가 동일한 모듈에 있기를 원하며 다음과 같이 기본 파일에서 사용할 것입니다.
use Math::Vector;
fn main() {
// ...
}
그러나 Rust의 모듈 시스템 (처음에는 약간 혼란 스럽습니다)은이를 수행하는 명백한 방법을 제공하지 않습니다. 전체 모듈을 하나의 파일로만 허용하는 것 같습니다. 소박하지 않습니까? 그렇지 않은 경우 어떻게해야합니까?
답변
Rust의 모듈 시스템은 실제로 믿을 수 없을 정도로 유연하며 코드가 파일에서 어떻게 구조화되어 있는지 숨기면서 원하는 구조를 노출 할 수 있습니다.
여기서 핵심 pub use
은 다른 모듈에서 식별자를 다시 내보낼 수 있는를 사용 하는 것입니다. Rust의 std::io
상자에는 하위 모듈의 일부 유형 이 .NET에서 사용하기 위해 다시 내보내std::io
지는 선례가 있습니다 .
편집 (2019-08-25) : 답변의 다음 부분은 꽤 오래 전에 작성되었습니다. 이러한 모듈 구조를
rustc
단독 으로 설정하는 방법을 설명합니다 . 오늘날 대부분의 사용 사례에 일반적으로 Cargo를 사용합니다. 다음은 여전히 유효하지만 일부 (예#![crate_type = ...]
:)가 이상하게 보일 수 있습니다. 이것은 권장되는 솔루션이 아닙니다.
예제를 적용하기 위해 다음 디렉터리 구조로 시작할 수 있습니다.
src/
lib.rs
vector.rs
main.rs
여기 있습니다 main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
그리고 당신 src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
그리고 마지막으로 src/vector.rs
:
// exports identifiers from private sub-modules in the current
// module namespace
pub use self::vector_a::VectorA;
pub use self::vector_b::VectorB;
mod vector_b; // private sub-module defined in vector_b.rs
mod vector_a { // private sub-module defined in place
#[derive(Debug)]
pub struct VectorA {
xs: Vec<i64>,
}
impl VectorA {
pub fn new() -> VectorA {
VectorA { xs: vec![] }
}
}
}
그리고 이것이 마법이 일어나는 곳입니다. 우리는 math::vector::vector_a
특별한 종류의 벡터를 구현 한 하위 모듈 을 정의했습니다 . 그러나 라이브러리의 클라이언트가 vector_a
하위 모듈 이 있다는 것을 신경 쓰지 않기를 바랍니다 . 대신 math::vector
모듈 에서 사용할 수 있도록하고 싶습니다 . 이것은 현재 모듈에서 식별자 pub use self::vector_a::VectorA
를 다시 내보내는으로 수행됩니다 vector_a::VectorA
.
그러나 특수한 벡터 구현을 다른 파일에 넣을 수 있도록이를 수행하는 방법을 물었습니다. 이것이 mod vector_b;
라인이하는 일입니다. Rust 컴파일러에게 vector_b.rs
해당 모듈의 구현을위한 파일 을 찾도록 지시합니다 . 여기에 src/vector_b.rs
파일이 있습니다.
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
클라이언트의 관점에서 사실 VectorA
과 VectorB
두 개의 서로 다른 파일에 두 개의 서로 다른 모듈에 정의는 완전히 불투명하다.
와 같은 디렉토리에있는 경우 다음을 사용 main.rs
하여 실행할 수 있습니다.
rustc src/lib.rs
rustc -L . main.rs
./main
일반적으로 Rust 책 의 “Crates and Modules”장은 꽤 좋습니다. 많은 예가 있습니다.
마지막으로, Rust 컴파일러는 자동으로 하위 디렉토리를 찾습니다. 예를 들어 위의 코드는 다음 디렉토리 구조에서 변경되지 않고 작동합니다.
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
컴파일 및 실행 명령도 동일하게 유지됩니다.
답변
Rust 모듈 규칙은 다음과 같습니다.
- 소스 파일 은 자체 모듈 일뿐입니다 (특수 파일 main.rs, lib.rs 및 mod.rs 제외).
- 디렉토리 는 모듈 경로 구성 요소입니다.
- mod.rs 파일 은 디렉토리의 모듈 일뿐 입니다 .
math 디렉토리의 matrix.rs 1 파일 은 모듈 일뿐math::matrix
입니다. 그것은 간단합니다. 파일 시스템에서 보는 것은 소스 코드에서도 찾을 수 있습니다. 이것은 파일 경로와 모듈 경로 2 의 일대일 대응입니다 .
따라서 구조체가 math 디렉토리의 matrix.rs 파일 안에 있기 때문에을 사용 하여 구조체 Matrix
를 가져올 수 있습니다 use math::matrix::Matrix
. 행복하지 않습니까? 당신은 use math::Matrix;
대신에 매우 선호 할 것입니다. 있을 수있다. 다음을 사용하여 math::matrix::Matrix
math / mod.rs에서 식별자 를 다시 내 보냅니다 .
pub use self::math::Matrix;
이 작업을 수행하는 또 다른 단계가 있습니다. Rust는 모듈을 로드 하기 위해 모듈 선언이 필요 합니다. mod math;
main.rs에 추가하십시오. 그렇게하지 않으면 다음과 같이 가져올 때 컴파일러에서 오류 메시지가 표시됩니다.
error: unresolved import `math::Matrix`. Maybe a missing `extern crate math`?
여기서 힌트는 오해의 소지가 있습니다. 물론 별도의 라이브러리를 작성하려는 경우를 제외하고는 추가 상자가 필요하지 않습니다.
main.rs 상단에 다음을 추가하십시오.
mod math;
pub use math::Matrix;
모듈 선언은 하위 모듈 vector
, matrix
및에 대해서도 필요합니다. , 을 다시 내보내려면로드해야하기 complex
때문 math
입니다. 식별자의 다시 내보내기는 식별자 모듈을로드 한 경우에만 작동합니다. 이 수단은 재수출에 식별자는 math::matrix::Matrix
당신이 작성해야합니다 mod matrix;
. math / mod.rs에서이 작업을 수행 할 수 있습니다. 따라서 다음 내용으로 파일을 만듭니다.
mod vector;
pub use self::vector::Vector;
mod matrix;
pub use self::matrix::Matrix;
mod complex;
pub use self::complex::Complex;
그리고 당신은 끝났습니다.
1 소스 파일 이름은 일반적으로 Rust에서 소문자로 시작합니다. 이것이 내가 Matrix.rs가 아닌 matrix.rs를 사용하는 이유입니다.
2 Java는 다릅니다. 으로 경로를 선언합니다 package
. 중복됩니다. 경로는 파일 시스템의 소스 파일 위치에서 이미 분명합니다. 파일 맨 위에있는 선언에서이 정보를 반복하는 이유는 무엇입니까? 물론 파일의 파일 시스템 위치를 찾는 대신 소스 코드를 빠르게 살펴 보는 것이 더 쉽습니다. 덜 헷갈 린다고 말하는 사람들을 이해할 수 있습니다.
답변
Rusts 순수 주의자들은 아마도 저를 이단자라고 부르고이 해결책을 싫어할 것입니다. 그러나 이것은 훨씬 더 간단합니다. 각각의 파일을 각자의 파일에서 수행 한 다음 mod.rs에서 ” include! “매크로를 사용하십시오.
include!("math/Matrix.rs");
include!("math/Vector.rs");
include!("math/Complex.rs");
이렇게하면 중첩 된 모듈이 추가되지 않고 복잡한 내보내기 및 다시 쓰기 규칙을 피할 수 있습니다. 간단하고 효과적이며 소란스럽지 않습니다.
답변
좋아, 잠시 동안 내 컴파일러와 싸웠고 마침내 작동하게되었습니다. (을 지적한 BurntSushi에게 감사드립니다 pub use
.
main.rs :
use math::Vec2;
mod math;
fn main() {
let a = Vec2{x: 10.0, y: 10.0};
let b = Vec2{x: 20.0, y: 20.0};
}
math / mod.rs :
pub use self::vector::Vec2;
mod vector;
수학 / 벡터 .rs
use std::num::sqrt;
pub struct Vec2 {
x: f64,
y: f64
}
impl Vec2 {
pub fn len(&self) -> f64 {
sqrt(self.x * self.x + self.y * self.y)
}
// other methods...
}
다른 구조체도 같은 방식으로 추가 할 수 있습니다. 참고 : 마스터가 아닌 0.9로 컴파일되었습니다.
답변
여기에 Rust 파일이 깊게 중첩 될 때 어떻게 포함하는지 추가하고 싶습니다. 다음과 같은 구조가 있습니다.
|-----main.rs
|-----home/
|---------bathroom/
|-----------------sink.rs
|-----------------toilet.rs
당신은 어떻게 액세스합니까 sink.rs
또는 toilet.rs
에서 main.rs
?
다른 사람들이 언급했듯이 Rust는 파일에 대한 지식이 없습니다. 대신 모든 것을 모듈과 하위 모듈로 간주합니다. 욕실 디렉토리에있는 파일에 액세스하려면 파일을 내보내거나 맨 위로 정렬해야합니다. 액세스하려는 디렉토리와 pub mod filename_inside_the_dir_without_rs_ext
파일 내부에 파일 이름을 지정 하면됩니다.
예.
// sink.rs
pub fn run() {
println!("Wash my hands for 20 secs!");
}
// toilet.rs
pub fn run() {
println!("Ahhh... This is sooo relaxing.")
}
-
디렉토리
bathroom.rs
안에 라는 파일을 만듭니다home
. -
파일 이름을 내 보냅니다.
// bathroom.rs pub mod sink; pub mod toilet;
-
home.rs
next 라는 파일을 만듭니다.main.rs
-
pub mod
bathroom.rs 파일// home.rs pub mod bathroom;
-
이내에
main.rs
// main.rs // Note: If you mod something, you just specify the // topmost module, in this case, home. mod home; fn main() { home::bathroom::sink::run(); }
use
문을 사용할 수도 있습니다.// main.rs // Note: If you mod something, you just specify the // topmost module, in this case, home. use home::bathroom::{sink, toilet}; fn main() { sink::run(); sink::toilet(); }
하위 모듈 내에 다른 형제 모듈 (파일) 포함
경우에 당신이 사용하려는 sink.rs
에서 toilet.rs
당신은 지정하여 모듈을 호출 할 수 있습니다, self
또는 super
키워드.
// inside toilet.rs
use self::sink;
pub fn run() {
sink::run();
println!("Ahhh... This is sooo relaxing.")
}
최종 디렉토리 구조
다음과 같은 결과를 얻게됩니다.
|-----main.rs
|-----home.rs
|-----home/
|---------bathroom.rs
|---------bathroom/
|-----------------sink.rs
|-----------------toilet.rs
위의 구조는 Rust 2018 이상에서만 작동합니다. 다음 디렉터리 구조는 2018 년에도 유효하지만 2015 년에 사용했던 방식입니다.
|-----main.rs
|-----home/
|---------mod.rs
|---------bathroom/
|-----------------mod.rs
|-----------------sink.rs
|-----------------toilet.rs
된 home/mod.rs
것과 동일 ./home.rs
하고 home/bathroom/mod.rs
동일하다 home/bathroom.rs
. Rust는 디렉토리와 같은 이름의 파일을 포함하면 컴파일러가 혼란 스러울 것이기 때문에 이렇게 변경했습니다. 2018 버전 (먼저 표시된 버전)은 해당 구조를 수정합니다.
자세한 내용은 이 저장소 를 참조 하고 전체적인 설명은 이 YouTube 비디오 를 참조하십시오 .
마지막으로 … 하이픈을 피하십시오! snake_case
대신 사용하십시오 .
중요 사항
당신은 반드시 깊은 파일이 최상위들에 의해 필요하지 않은 경우에도 가기 배럴 모든 파일을.
즉, sink.rs
을 발견 toilet.rs
하려면 위의 방법을 사용하여 main.rs
!
다시 말해서, 당신이 그들을 완전히 노출하지 않는 한 do pub mod sink;
또는 use self::sink;
inside toilet.rs
는 작동 하지 않습니다main.rs
!
따라서 항상 파일을 맨 위에 배치하는 것을 잊지 마십시오!