모듈을 서로 다른 파일로 나누기

모듈을 서로 다른 파일로 나누기 (Separating Modules into Different Files)

지금까지 이 장의 예시들은 한 파일에 여러 모듈을 정의했어요. 모듈이 커지면 그 정의를 별도의 파일로 옮기고 싶어지죠. 그렇게 하면 코드를 탐색하기 쉬워져요. 이번 절에서는 모듈을 파일로 추출하는 방법을 살펴볼게요. 코드를 여러 파일로 나눠도 모듈 트리는 그대로 유지되고, 호출 코드는 조금도 바꿀 필요가 없다는 걸 확인할 수 있어요.

출처: The Rust Book — 모듈을 서로 다른 파일로 나누기

모듈을 파일로 추출하기

예를 들어 여러 레스토랑 모듈이 있던 Listing 7-17의 코드에서 시작해 볼게요. 모든 모듈을 크레이트 루트 파일에 정의하는 대신, 모듈들을 파일로 추출할게요. 이 경우 크레이트 루트 파일은 src/lib.rs인데, 이 과정은 크레이트 루트 파일이 src/main.rs인 바이너리 크레이트에서도 동일하게 작동해요.

먼저 front_of_house 모듈을 자체 파일로 추출할게요. front_of_house 모듈의 중괄호 안 코드를 제거하고 mod front_of_house; 선언만 남겨서, src/lib.rs가 Listing 7-21의 코드를 담게 해요. Listing 7-22의 src/front_of_house.rs 파일을 만들기 전까지는 이 코드가 컴파일되지 않는다는 점을 기억하세요.

mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

다음으로, 중괄호 안에 있던 코드를 src/front_of_house.rs라는 새 파일에 넣어요. Listing 7-22가 그 예시예요. 컴파일러는 크레이트 루트에서 front_of_house라는 이름의 모듈 선언을 만났기 때문에 이 파일을 찾아보는 걸 알아요.

pub mod hosting {
    pub fn add_to_waitlist() {}
}

파일은 모듈 트리에서 mod 선언으로 한 번만 불러오면 된다는 점을 기억하세요. 컴파일러가 파일이 프로젝트의 일부라는 것(그리고 mod 문을 어디에 뒀는지에 따라 코드가 모듈 트리의 어디에 있는지)을 알게 되면, 프로젝트의 다른 파일들은 "모듈 트리에서 항목을 가리키는 경로" 절에서 다룬 것처럼, 그 파일이 선언된 위치로 가는 경로를 사용해 로드된 파일의 코드를 참조해야 해요. 다시 말해 mod는 다른 프로그래밍 언어에서 본 "include" 연산이 아니에요.

다음으로 hosting 모듈을 자체 파일로 추출할게요. hosting이 루트 모듈이 아니라 front_of_house의 자식 모듈이므로 과정이 조금 달라요. hosting의 파일은 모듈 트리에서 조상들의 이름을 딴 새 디렉터리, 여기서는 src/front_of_house에 놓을게요.

hosting을 옮기기 시작하려면 src/front_of_house.rshosting 모듈의 선언만 담도록 바꿔요.

pub mod hosting;

그 다음 src/front_of_house 디렉터리와 그 안에 hosting 모듈에서 만들었던 정의를 담을 hosting.rs 파일을 만들어요.

pub fn add_to_waitlist() {}

대신 hosting.rssrc 디렉터리에 둔다면, 컴파일러는 hosting.rs의 코드가 크레이트 루트에 선언된 hosting 모듈에 있어야 한다고 기대할 거예요. front_of_house 모듈의 자식으로 선언된 게 아니라요. 어떤 모듈의 코드를 어떤 파일에서 찾을지에 대한 컴파일러 규칙 덕분에 디렉터리와 파일이 모듈 트리와 더 밀접하게 일치해요.

대체 파일 경로 (Alternate File Paths)

지금까지 러스트 컴파일러가 쓰는 가장 관용적인 파일 경로를 다뤘는데, 러스트는 더 오래된 스타일의 파일 경로도 지원해요. 크레이트 루트에 선언된 front_of_house 모듈의 경우 컴파일러는 모듈의 코드를 다음 위치에서 찾아요.

  • src/front_of_house.rs (지금까지 다룬 방식)
  • src/front_of_house/mod.rs (더 오래된 스타일이지만 여전히 지원되는 경로)

front_of_house의 하위 모듈인 hosting 모듈의 경우 컴파일러는 모듈의 코드를 다음 위치에서 찾아요.

  • src/front_of_house/hosting.rs (지금까지 다룬 방식)
  • src/front_of_house/hosting/mod.rs (더 오래된 스타일이지만 여전히 지원되는 경로)

같은 모듈에 두 스타일을 모두 쓰면 컴파일러 오류가 나요. 같은 프로젝트의 서로 다른 모듈에 두 스타일을 섞어 쓰는 것은 허용되지만, 프로젝트를 탐색하는 사람들에게는 혼란스러울 수 있어요.

mod.rs라는 이름의 파일을 쓰는 스타일의 주된 단점은 프로젝트에 mod.rs라는 파일이 많이 생길 수 있다는 점이에요. 편집기에서 여러 개를 동시에 열어 두면 헷갈리기 쉽죠.

각 모듈의 코드를 별도의 파일로 옮겼고 모듈 트리는 그대로 유지돼요. 정의가 서로 다른 파일에 있더라도 eat_at_restaurant 안의 함수 호출은 수정 없이 동작해요. 이 기법 덕분에 모듈이 커질 때 새 파일로 옮길 수 있어요.

src/lib.rspub use crate::front_of_house::hosting 구문도 바뀌지 않았고, use가 크레이트의 일부로 컴파일되는 파일에는 아무 영향도 주지 않는다는 점을 기억하세요. mod 키워드가 모듈을 선언하고, 러스트는 그 모듈과 같은 이름의 파일에서 그 모듈에 들어갈 코드를 찾아요.

요약 (Summary)

러스트는 패키지를 여러 크레이트로, 크레이트를 모듈로 쪼갤 수 있게 해 줘요. 그래서 한 모듈에 정의된 항목을 다른 모듈에서 참조할 수 있어요. 절대 경로나 상대 경로를 지정해서 그렇게 할 수 있고, use 문으로 이 경로들을 스코프 안으로 가져와서 그 스코프에서 항목을 여러 번 쓸 때 더 짧은 경로를 쓸 수 있어요. 모듈 코드는 기본적으로 비공개이지만, pub 키워드를 붙여 정의를 공개로 만들 수 있어요.

다음 장에서는 잘 정리된 코드 안에서 쓸 수 있는 표준 라이브러리의 컬렉션 데이터 구조 몇 가지를 살펴볼게요.

더 알아보기 (Learn more)