your programing

모듈을 여러 파일로 분할

lovepro 2020. 10. 7. 08:00
반응형

모듈을 여러 파일로 분할


각각 자체 파일에 여러 구조체가있는 모듈을 갖고 싶습니다 . 사용하여 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![] }
    }
}

클라이언트의 관점에서 사실 VectorAVectorB두 개의 서로 다른 파일에 두 개의 서로 다른 모듈에 정의는 완전히 불투명하다.

와 같은 디렉토리에있는 경우 다음을 사용 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 모듈 규칙은 다음과 같습니다.

  1. 소스 파일 자체 모듈 일뿐입니다 (특수 파일 main.rs, lib.rs 및 mod.rs 제외).
  2. 디렉토리 모듈 경로 구성 요소입니다.
  3. The file mod.rs is just the directory's module.

The file matrix.rs1 in the directory math is just the module math::matrix. It's easy. What you see on your filesystem you also find in your source code. This is an one-to-one correspondence of file paths and module paths2.

So you can import a struct Matrix with use math::matrix::Matrix, because the struct is inside the file matrix.rs in a directory math. Not happy? You'd prefer use math::Matrix; very much instead, don't you? It's possible. Re-export the identifier math::matrix::Matrix in math/mod.rs with:

pub use self::math::Matrix;

There's another step to get this working. Rust needs a module declaration to load the module. Add a mod math; in main.rs. If you don't do that, you get an error message from the compiler when importing like this:

error: unresolved import `math::Matrix`. Maybe a missing `extern crate math`?

The hint is misleading here. There's no need for additional crates, except of course you really intend to write a separate library.

Add this at the top of main.rs:

mod math;
pub use math::Matrix;

The module declaration is also neccessary for the submodules vector, matrix and complex, because math needs to load them to re-export them. A re-export of an identifier only works if you have loaded the module of the identifier. This means, to re-export the identifier math::matrix::Matrix you need to write mod matrix;. You can do this in math/mod.rs. Therefore create the file with this content:

mod vector;
pub use self::vector::Vector;

mod matrix;
pub use self::matrix::Matrix;

mod complex;
pub use self::complex::Complex;

Aaaand you are done.


1Source file names usually start with a lowercase letter in Rust. That's why I use matrix.rs and not Matrix.rs.

2Java's different. You declare the path with package, too. It's redundant. The path is already evident from the source file location in the filesystem. Why repeat this information in a declaration at the top of the file? Of course sometimes it's easier to have a quick look at the source code instead of finding out the filesystem location of the file. I can understand people who say it's less confusing.


Alright, fought my compiler for a while and finally got it to work(thanks to BurntSushi for pointing out 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;

math/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...
}

Other structs could be added in the same manner. NOTE: compiled with 0.9, not master.


Rusts purists will probably call me a heretic and hate this solution, but this is much simpler: just do each thing in its own file, then use the "include!" macro in mod.rs:

include!("math/Matrix.rs");
include!("math/Vector.rs");
include!("math/Complex.rs");

That way you get no added nested modules, and avoid complicated export and rewrite rules. Simple, effective, no fuss.

참고URL : https://stackoverflow.com/questions/22596920/split-a-module-across-several-files

반응형