프로그램 구조

모듈과 가시성

import와 export로 두 파일을 연결하고 루트를 지정하며 비공개 이름과 순환 import 오류를 고칩니다.

프로그램을 여러 파일로 나누고 다른 파일에서 사용할 이름을 고르세요. 두 파일로 만든 학습 계획 프로그램을 실행한 뒤 비공개 이름과 순환 import 오류를 고칩니다.

첫 프로그램을 따라 topaz를 설치하세요. .tpz 파일 하나가 모듈 하나입니다. 별도의 module 선언은 필요하지 않습니다.

두 파일로 프로그램 실행하기

study-plan 프로젝트가 아직 없는 작업 폴더에서 다음 명령을 실행하세요.

BASH
topaz init --root study-plan
cd study-plan

init은 topaz.toml과 src/main.tpz를 만듭니다. 생성한 매니페스트는 유지하세요. 아래 코드로 src/plan.tpz를 추가하고 src/main.tpz를 바꾸세요. 잠금 파일까지 만들면 다음 구조가 됩니다.

study-plan/
├── topaz.toml
├── topaz.lock
└── src/
    ├── main.tpz
    └── plan.tpz

과제 데이터와 함수는 src/plan.tpz에 저장하세요.

TOPAZ
export record 학습과제 {
    제목: string,
    분: int,
    완료: bool = false,
}

function 분해석(텍스트: string) -> Result<int, string> {
    match toInt(텍스트) {
        case Some(값) if 값 > 0 => Ok(값)
        case _ => Err("minutes must be a positive integer")
    }
}

export function 과제만들기(
    제목: string,
    분문자열: string,
    완료: bool = false,
) -> Result<학습과제, string> {
    let 분 = 분해석(분문자열)?
    Ok(학습과제 { 제목: 제목, 분: 분, 완료: 완료 })
}

export function 요약(과제들: Array<학습과제>) -> string {
    let mut 남음 = 0
    for 과제 in 과제들 {
        if !과제.완료 {
            남음 = 남음 + 과제.분
        }
    }
    "tasks={과제들.length}, remaining={남음} minutes"
}

src/main.tpz에서는 애플리케이션이 사용할 세 이름을 가져옵니다.

TOPAZ
import src.plan { 학습과제, 과제만들기, 요약 }

export function main(인자: Array<string>, 표준입력: string) -> Result<int, string> {
    let 과제들: Array<학습과제> = [
        과제만들기("Run first program", "10", true)?,
        과제만들기("Build application", "25", false)?,
    ]
    print(요약(과제들))
    Ok(0)
}

topaz.toml이 있는 study-plan 폴더에서 실행하세요.

BASH
topaz lock --root .
topaz check --root . --locked
topaz run --root . --locked

lock은 topaz.lock을 만듭니다. 검사는 종료 코드 0으로 끝나고 프로그램은 요약을 출력합니다.

출력
tasks=2, remaining=25 minutes

src.plan은 지정한 루트 아래의 src/plan.tpz를 가리킵니다. 컴파일러는 진입 파일과 가져온 모듈을 검사하며, 각 모듈의 import도 따라갑니다. 이렇게 모은 파일을 컴파일 단위라고 합니다. 이 진입 파일과 연결되지 않은 파일은 검사하지 않습니다.

공개할 이름 고르기

선언은 기본적으로 비공개입니다. 다른 모듈에서 사용하려면 앞에 export를 붙이세요. 이 예제에서는 학습과제, 과제만들기, 요약을 공개하며 분해석은 비공개로 둡니다.

src/main.tpz에서 분해석을 가져오거나 접근하면 검사가 실패합니다. 공개한 과제만들기를 호출하세요. 도우미 함수도 공개하려는 의도라면 src/plan.tpz의 선언 앞에 export를 붙이세요. 가져온 바인딩은 읽기 전용입니다.

할 일import 형식
이름 선택import src.plan { 학습과제, 과제만들기 }
선택한 이름에 별칭 지정import src.plan { 요약 as 요약그리기 }
접두 이름으로 묶기import src.plan as 계획

마지막 형식은 컴파일할 때 공개한 이름을 찾는 접두 이름인 네임스페이스를 만듭니다. 계획.과제만들기(...)처럼 호출하세요. 네임스페이스 자체는 실행 중 사용하는 값이 아닙니다.

타입을 표기할 때는 계획.학습과제를 사용할 수 있습니다. 학습과제 { ... }로 값을 만들려면 학습과제를 직접 선택해 가져오세요. 계획.학습과제 { ... } 형식은 거부합니다. import src.plan as 계획 { 요약 }이라고 썼다면 위의 분리된 import 형식 중 하나로 바꾸세요.

올바른 루트에서 파일 찾기

점을 구분자로 쓰는 모듈 경로를 루트 아래의 정확한 파일·폴더 이름과 맞추세요. import는 다른 항목보다 앞인 파일 맨 위에 둡니다.

패키지 명령은 topaz.toml에서 진입 파일, 의존성, 빌드 대상을 읽습니다. 파일을 직접 지정하면 진입 파일의 폴더가 기본 루트입니다. 상위 폴더를 루트로 삼으려면 --root를 지정하세요. src.plan을 찾지 못하면 --root와 src/plan.tpz의 위치를 함께 확인합니다.

의존 모듈은 자신을 가져오는 모듈보다 먼저 한 번 초기화됩니다. 가져온 모듈에는 선언과 바인딩을 쓸 수 있습니다. 함수 밖의 최상위 루프·대입문은 거부하므로 함수 안으로 옮기고 진입 파일에서 호출하세요.

순환 import 끊기

별도 폴더에 다음 코드를 a.tpz로 저장하세요.

import b

export function 에이에서() -> int {
    1
}

그 옆에 다음 코드를 b.tpz로 저장하세요.

import a

export function 비에서() -> int {
    2
}

그 폴더에서 topaz check a.tpz --root .를 실행하면 0이 아닌 코드로 끝나며 순환 관계를 알립니다.

출력
error[TPZ3006]: import cycle: a -> b -> a
 --> a.tpz:1:8
  |
1 | import b
  |        ^

a.tpz: 1 diagnostic

a.tpz와 b.tpz의 공통 선언을 세 번째 모듈로 옮기고 두 파일에서 가져오세요. 한쪽 방향의 의존성을 없애는 방법도 있습니다. 타입에 쓰는 import를 포함해 모든 import 관계가 순환 검사 대상입니다.

컴파일러가 거부하는 형식

컴파일러는 use, 문자열·템플릿 경로, 별칭과 선택 목록의 결합, 부수 효과만을 위한 import를 거부합니다. 공개 목록, 와일드카드 공개, 재공개, 공개 위치의 이름 변경, export let mut도 거부합니다. import 경로는 루트 밖으로 나갈 수 없으며 네임스페이스로 비공개 이름에 접근할 수 없습니다.

첫 애플리케이션에서 이 프로그램에 테스트를 추가하고 빌드하세요. 의존성과 잠금은 패키지와 배포를 보세요. 익숙한 문법을 지원 형식과 비교하려면 금지·유예 형식을 보세요.