English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
모든 프로그래밍 언어가 코드를 조직하지 못하면 깊이 이해하기 어렵습니다. 거의 모든 소프트웨어 제품이 하나의 소스 파일로 컴파일된 것은 없습니다.
이 튜토리얼에서는 현재까지 모든 프로그램이 하나의 파일에서 작성되었으며, 이는 Rust 언어의 문법과 개념을 학습하기 쉽게 하기 위해 주어졌습니다.
프로젝트에 있어서, 코드 조직은 매우 중요합니다.
Rust에는 세 가지 중요한 조직 개념이 있습니다: 박스, 패키지, 모듈.
"박스"는 바이너리 프로그램 파일이나 라이브러리 파일로, "패키지"에 존재합니다.
"박스"는 트리 구조이며, 그 트리의 뿌리는 컴파일러가 실행될 때 컴파일된 소스 파일로부터 컴파일된 프로그램입니다.
주의: "바이너리 프로그램 파일"은 "바이너리 실행 파일"이 아니며, 목표 기계 언어를 포함하는 파일임을 확정할 수 있을 뿐, 파일 포맷은 컴파일 환경에 따라 다릅니다.
Cargo를 사용하여 new 명령어를 실행하여 Rust 프로젝트를 생성할 때, 프로젝트 디렉토리 아래에 Cargo.toml 파일이 생성됩니다. 프로젝트는 실제로 패키지이며, 패키지는 Cargo.toml 파일을 통해 관리되어야 하며, 이 파일은 패키지의 기본 정보와 의존성을 설명합니다.
패키지는 최대한 하나의 라이브러리 "박스"를 포함할 수 있으며, 얼마든지 많은 바이너리 "박스"를 포함할 수 있지만, 최소한 하나의 "박스"(라이브러리 또는 바이너리 박스)를 포함해야 합니다.
cargo new 명령어를 사용하여 패키지를 생성한 후, src 디렉토리 아래에 main.rs 소스 파일이 생성됩니다. Cargo는 이 파일을 바이너리 박스의 뿌리로 기본적으로 설정하며, 컴파일된 바이너리 박스는 패키지 이름과 동일합니다.
소프트웨어 엔지니어링에 있어서, 우리는 일반적으로 사용하는 프로그래밍 언어의 조직 규범에 따라 조직을 합니다. 조직 모듈의 주요 구조는 대부분 트리입니다. Java의 조직 기능 모듈의 주요 단위는 클래스(Class)이고, JavaScript의 모듈 조직 방식은 함수(Function)입니다.
이러한 先进的 언어의 조직 단위는 계층적으로 포함될 수 있습니다. 파일 시스템의 디렉토리 구조와 마찬가지로. Rust의 조직 단위는 모듈(Modular)입니다.
mod nation { mod 정부 { fn 지배() {} } mod congress { fn 법제화() {} } mod court { fn 법적() {} } }
이는 법치 국가를 설명하는 단락입니다: 국가(국가)는 정부(정부), 의회(의회), 법원(법원)으로 구성되어 있으며, 각각 행정, 법제화, 법적 기능을 가집니다. 이를 트리 구조로 변환할 수 있습니다:
국가 ├── 정부 │ └── 지배 ├── 의회 │ └── 법제화 └── 법원 └── 법적
파일 시스템에서, 디렉토리 구조는 일반적으로 경로 문자열에서 대시(/)로 객체의 위치를 나타내며, Rust의 경로 구분자는 ::입니다.
경로는 절대 경로와 상대 경로로 나뉩니다. 절대 경로는 crate 키워드에서 시작됩니다. 상대 경로는 self 또는 super 키워드나 식별자에서 시작됩니다. 예를 들어:
crate::nation::government::govern();
govern 함수를 설명하는 절대 경로입니다. 상대 경로는 다음과 같이 표현할 수 있습니다:
nation::government::govern();
이제 유사한 모듈 구조를 소스 프로그램에서 정의하고 메인 함수에서 경로를 사용하여 시도해 보세요.
이렇게 하면, government 모듈과 그 안의 함수가 모두 private이므로 접근할 수 없습니다.
Rust에는 두 가지 간단한 접근 권한이 있습니다: public(public)과 private(private).
기본적으로, modifier가 없는 경우 모듈 내 멤버의 접근 권한은 private입니다.
public 권한을 사용하려면 pub 키워드를 사용해야 합니다.
private 모듈은 동일한 수준이나 하위 위치에서만 접근할 수 있으며, 외부에서 접근할 수 없습니다.
mod nation { pub mod government { pub fn govern() {} } mod congress { pub fn legislate() {} } mod court { fn judicial() { super::congress::legislate(); } } } fn main() { nation::government::govern(); }
이 프로그램은 컴파일 가능합니다. court 모듈에서 super의 접근 방법을 주의 깊게 관찰하십시오.
모듈 내에서 구조체가 정의되었을 경우, 구조체 자체는 기본적으로 private이며, 그 필드도 기본적으로 private입니다. 따라서 모듈 내 구조체 및 그 필드를 사용하려면 pub 선언이 필요합니다:
mod back_of_house { pub struct Breakfast { pub toast: String, seasonal_fruit: String, } impl Breakfast { pub fn summer(toast: &str) -> Breakfast { Breakfast { toast: String::from(toast), seasonal_fruit: String::from("peaches"), } } } } pub fn eat_at_restaurant() { let mut meal = back_of_house::Breakfast::summer("Rye"); meal.toast = String::from("Wheat"); println!("I'd like {} toast please", meal.toast); } fn main() { eat_at_restaurant() }
실행 결과:
I'd like Wheat toast please
암시적 클래스 열거 항목은 필드를 포함할 수 있지만, 유사한 성질을 가지지 않습니다:
mod SomeModule { pub enum Person { King { name: String }, Quene } } fn main() { let person = SomeModule::Person::King { name: String::from("Blue") }; match person { SomeModule::Person::King { name } => { println!("{}", name); } _ => {} } }
실행 결과:
Blue
Java를 사용한 개발자는 일반적으로 가장 외부의 class 블록을 싫어합니다 - 그 이름은 파일 이름과 같으며, 그것은 파일 컨테이너를 의미하지만, 어렵게도 이를 반복하여 "이 클래스는 파일에 포함된 클래스입니다"를 강조해야 합니다.
그러나 이렇게 하면 몇 가지 장점이 있습니다: 최소한 개발자가 클래스 包装의 존재를 명확히 인식할 수 있으며, 클래스의 상속 관계를 명확히 설명할 수 있습니다.
Rust에서 모듈은 Java의 클래스 包装과 같지만, 파일의 첫 번째 줄에 메인 함수를 쓸 수 있어 이를 어떻게 설명해야 하나요?
각 Rust 파일의 내용은 모두 "발견하기 어려운" 모듈입니다。
이를 보여주기 위해 두 개의 파일을 사용하겠습니다:
실행 결과:
This is the main module. This is the 2nd module.
use 키워드는 모듈 식별자를 현재 범위에 도입할 수 있습니다:
mod nation { pub mod government { pub fn govern() {} } } use crate::nation::government::govern; fn main() { govern(); }
이 프로그램은 컴파일될 수 있습니다.
use 키워드는 govern 식별자를 현재 모듈에 임포트했기 때문에 직접 사용할 수 있습니다.
이렇게 하면 지역 모듈 경로가 길어지는 문제를 해결할 수 있습니다.
물론, 두 개의 동일한 이름이 존재하며 동시에 임포트되어야 하는 경우에는 as 키워드를 사용하여 식별자에 별명을 추가할 수 있습니다:
mod nation { pub mod government { pub fn govern() {} } pub fn govern() {} } use crate::nation::government::govern; use crate::nation::govern as nation_govern; fn main() { nation_govern(); govern(); }
여기서 두 govern 함수가 있습니다. 하나는 nation 아래의 것이고, 하나는 government 아래의 것이며, 우리는 nation 아래의 것을 as를 사용하여 nation_govern이라는 별명으로 가져옵니다. 두 이름을 동시에 사용할 수 있습니다.
use 키워드는 pub 키워드와 함께 사용될 수 있습니다:
mod nation { pub mod government { pub fn govern() {} } pub use government::govern; } fn main() { nation::govern(); }
Rust 공식 표준 라이브러리 사전:https://doc.rust-lang.org/stable/std/all.html
이 장의 개념을 배웠다면, 시스템 라이브러리를 쉽게 임포트하여 프로그램을 개발할 수 있습니다:
use std::f64::consts::PI; fn main() { println!("{}", (PI / 2.0).sin()); }
실행 결과:
1
모든 시스템 라이브러리 모듈은 기본적으로 임포트되며, 사용할 때는 use 키워드를 사용하여 경로를 간소화하여 쉽게 사용할 수 있습니다.