Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

명명 규칙

대소문자 표기는 RFC 430을 따릅니다 (C-CASE)

Rust의 기본 명명 규칙은 RFC 430에 설명되어 있습니다.

일반적으로 Rust는 “타입 수준” 구성 요소(타입과 트레이트)에는 UpperCamelCase를, “값 수준” 구성 요소에는 snake_case를 사용하는 경향이 있습니다. 더 정확하게는 다음과 같습니다:

항목규칙
크레이트불명확함
모듈snake_case
타입UpperCamelCase
트레이트UpperCamelCase
열거형 배리언트UpperCamelCase
함수snake_case
메서드snake_case
일반 생성자new 또는 with_more_details
변환 생성자from_some_other_type
매크로snake_case!
지역 변수snake_case
정적 변수SCREAMING_SNAKE_CASE
상수SCREAMING_SNAKE_CASE
타입 매개변수간결한 UpperCamelCase, 보통 대문자 한 글자: T
라이프타임짧은 lowercase, 보통 한 글자: 'a, 'de, 'src
기능기능 이름 규칙은 불명확합니다. 다만 C-FEATURE를 참고하십시오.

UpperCamelCase에서는 약어와 복합어의 축약형을 한 단어로 취급합니다. UUID 대신 Uuid를, USize 대신 Usize를, StdIn 대신 Stdin을 사용하십시오. snake_case에서는 약어와 축약형을 소문자로 씁니다: is_xid_start.

snake_case나 SCREAMING_SNAKE_CASE에서 “단어“는 마지막 “단어“가 아닌 한 절대 한 글자로 이루어져서는 안 됩니다. 따라서 b_tree_map이 아니라 btree_map을 쓰지만, PI2가 아니라 PI_2를 씁니다.

크레이트 이름에는 -rs나 -rust를 접미사나 접두사로 사용해서는 안 됩니다. 모든 크레이트는 Rust입니다! 사용자에게 이 사실을 계속 상기시키는 것은 아무 의미가 없습니다.

표준 라이브러리의 예

표준 라이브러리 전체입니다. 이 가이드라인은 쉬울 것입니다!

임시 변환은 as_, to_, into_ 관례를 따릅니다 (C-CONV)

변환은 메서드로 제공해야 하며, 이름에는 다음과 같은 접두사를 붙입니다:

접두사비용소유권
as_무비용빌림 -> 빌림
to_높음빌림 -> 빌림
빌림 -> 소유 (Copy가 아닌 타입)
소유 -> 소유 (Copy 타입)
into_가변소유 -> 소유 (Copy가 아닌 타입)

예를 들면 다음과 같습니다.

  • str::as_bytes()는 str을 UTF-8 바이트의 슬라이스로 보는 뷰를 제공하며, 비용이 들지 않습니다. 입력은 빌린 &str이고 출력은 빌린 &[u8]입니다.
  • Path::to_str는 운영 체제 경로의 바이트에 대해 비용이 큰 UTF-8 검사를 수행합니다. 입력과 출력은 모두 빌린 것입니다. 이 메서드는 런타임에 무시할 수 없는 비용이 들기 때문에 as_str라고 부르는 것은 올바르지 않습니다.
  • str::to_lowercase()는 str에 대해 유니코드 규칙에 맞는 소문자 버전을 만들어 내는데, 이 과정에서 문자열의 문자를 순회해야 하며 메모리 할당이 필요할 수도 있습니다. 입력은 빌린 &str이고 출력은 소유된 String입니다.
  • f64::to_radians()는 부동소수점 값을 도(degree)에서 라디안으로 변환합니다. 입력은 f64입니다. f64는 복사 비용이 적으므로 참조 &f64를 전달할 필요가 없습니다. 입력이 소비되지 않으므로 이 함수를 into_radians라고 부르면 오해를 일으킬 수 있습니다.
  • String::into_bytes()는 String의 내부 Vec<u8>을 꺼내며, 비용이 들지 않습니다. 이 메서드는 String의 소유권을 가져와 소유된 Vec<u8>을 반환합니다.
  • BufReader::into_inner()는 버퍼링된 리더의 소유권을 가져와 내부 리더를 꺼내며, 비용이 들지 않습니다. 버퍼에 있던 데이터는 버려집니다.
  • BufWriter::into_inner()는 버퍼링된 라이터의 소유권을 가져와 내부 라이터를 꺼내는데, 이때 버퍼에 남은 데이터를 플러시해야 하므로 비용이 클 수 있습니다.

as_와 into_ 접두사가 붙은 변환은 일반적으로 추상화 수준을 낮추며, 내부 표현에 대한 뷰를 노출하거나(as) 데이터를 분해하여 내부 표현으로 만듭니다(into). 반면 to_ 접두사가 붙은 변환은 일반적으로 같은 추상화 수준에 머무르면서, 한 표현을 다른 표현으로 바꾸는 작업을 어느 정도 수행합니다.

어떤 타입이 단일 값을 감싸서 더 높은 수준의 의미를 부여하는 경우, 감싸진 값에 대한 접근은 into_inner() 메서드로 제공해야 합니다. 이는 BufReader처럼 버퍼링을 제공하는 래퍼, GzDecoder처럼 인코딩이나 디코딩을 제공하는 래퍼, AtomicBool처럼 원자적 접근을 제공하는 래퍼, 또는 이와 유사한 의미를 제공하는 모든 래퍼에 적용됩니다.

변환 메서드 이름의 mut 한정자가 반환 타입의 일부를 나타낸다면, 타입에 나타나는 그대로의 위치에 와야 합니다. 예를 들어 Vec::as_mut_slice는 mut 슬라이스를 반환하며, 이름 그대로의 동작을 합니다. 이 이름이 as_slice_mut보다 선호됩니다.

#![allow(unused)]
fn main() {
// Return type is a mut slice.
fn as_mut_slice(&mut self) -> &mut [T];
}
표준 라이브러리의 더 많은 예

게터 이름은 Rust 관례를 따릅니다 (C-GETTER)

몇 가지 예외를 제외하면, Rust 코드에서는 게터에 get_ 접두사를 사용하지 않습니다.

#![allow(unused)]
fn main() {
pub struct S {
    first: First,
    second: Second,
}

impl S {
    // Not get_first.
    pub fn first(&self) -> &First {
        &self.first
    }

    // Not get_first_mut, get_mut_first, or mut_first.
    pub fn first_mut(&mut self) -> &mut First {
        &mut self.first
    }
}
}

get이라는 이름은 게터로 가져올 수 있는 것이 합리적으로 보아 단 하나뿐이고 명확할 때에만 사용합니다. 예를 들어 Cell::get은 Cell의 내용에 접근합니다.

경계 검사와 같은 런타임 검증을 수행하는 게터의 경우, unsafe _unchecked 변형을 추가하는 것을 고려하십시오. 일반적으로 이러한 변형은 다음과 같은 시그니처를 가집니다.

#![allow(unused)]
fn main() {
fn get(&self, index: K) -> Option<&V>;
fn get_mut(&mut self, index: K) -> Option<&mut V>;
unsafe fn get_unchecked(&self, index: K) -> &V;
unsafe fn get_unchecked_mut(&mut self, index: K) -> &mut V;
}

게터와 변환(C-CONV)의 차이는 미묘할 수 있으며 항상 명확하게 구분되는 것은 아닙니다. 예를 들어 TempDir::path는 임시 디렉터리의 파일 시스템 경로에 대한 게터로 이해할 수 있는 반면, TempDir::into_path는 임시 디렉터리를 삭제할 책임을 호출자에게 넘기는 변환입니다. path는 게터이므로 이를 get_path나 as_path라고 부르는 것은 올바르지 않습니다.

표준 라이브러리의 예

컬렉션에서 이터레이터를 생성하는 메서드는 iter, iter_mut, into_iter를 따릅니다 (C-ITER)

RFC 199에 따릅니다.

U 타입의 요소를 담는 컨테이너의 경우, 이터레이터 메서드의 이름은 다음과 같이 지어야 합니다.

#![allow(unused)]
fn main() {
fn iter(&self) -> Iter             // Iter implements Iterator<Item = &U>
fn iter_mut(&mut self) -> IterMut  // IterMut implements Iterator<Item = &mut U>
fn into_iter(self) -> IntoIter     // IntoIter implements Iterator<Item = U>
}

이 가이드라인은 개념적으로 동질적인 컬렉션인 데이터 구조에 적용됩니다. 반례로, str 타입은 유효한 UTF-8임이 보장되는 바이트의 슬라이스입니다. 이는 개념적으로 동질적인 컬렉션보다 미묘한 차이가 있으므로, iter/iter_mut/into_iter 계열의 이터레이터 메서드를 제공하는 대신 바이트 단위로 순회하는 str::bytes와 문자 단위로 순회하는 str::chars를 제공합니다.

이 가이드라인은 함수가 아닌 메서드에만 적용됩니다. 예를 들어 url 크레이트의 percent_encode는 퍼센트 인코딩된 문자열 조각에 대한 이터레이터를 반환합니다. 여기에 iter/iter_mut/into_iter 규칙을 적용해도 더 명확해지는 것은 없습니다.

표준 라이브러리의 예

이터레이터 타입 이름은 해당 타입을 생성하는 메서드의 이름과 일치합니다 (C-ITER-TY)

into_iter()라는 메서드는 IntoIter라는 타입을 반환해야 하며, 이터레이터를 반환하는 다른 모든 메서드도 마찬가지입니다.

이 가이드라인은 주로 메서드에 적용되지만, 함수에도 적용하는 것이 타당한 경우가 많습니다. 예를 들어 url 크레이트의 percent_encode 함수는 PercentEncode라는 이터레이터 타입을 반환합니다.

이러한 타입 이름은 vec::IntoIter처럼 소속 모듈을 접두어로 붙였을 때 가장 자연스럽습니다.

표준 라이브러리의 예

기능 이름에는 의미 없는 자리 채움용 단어를 넣지 않습니다 (C-FEATURE)

use-abc나 with-abc처럼 아무 의미도 전달하지 않는 단어를 Cargo 기능의 이름에 넣지 마십시오. 기능 이름은 바로 abc로 지으십시오.

이 문제는 Rust 표준 라이브러리에 대한 선택적 의존성이 있는 크레이트에서 가장 흔하게 발생합니다. 이를 올바르게 처리하는 표준적인 방법은 다음과 같습니다.

# In Cargo.toml

[features]
default = ["std"]
std = []
#![allow(unused)]
fn main() {
// In lib.rs
#![no_std]

#[cfg(feature = "std")]
extern crate std;
}

기능 이름을 use-std나 with-std, 또는 std가 아닌 어떤 창의적인 이름으로도 짓지 마십시오. 이 명명 규칙은 Cargo가 선택적 의존성에 대해 추론하는 암시적 기능의 이름 규칙과 일치합니다. Serde와 Rust 표준 라이브러리에 대한 선택적 의존성이 있는 크레이트 x를 생각해 봅시다.

[package]
name = "x"
version = "0.1.0"

[features]
std = ["serde/std"]

[dependencies]
serde = { version = "1.0", optional = true }

x에 의존할 때, features = ["serde"]로 선택적 Serde 의존성을 활성화할 수 있습니다. 마찬가지로 features = ["std"]로 선택적 표준 라이브러리 의존성을 활성화할 수 있습니다. Cargo가 선택적 의존성에 대해 추론하는 암시적 기능의 이름은 use-serde나 with-serde가 아니라 serde이므로, 명시적 기능도 같은 방식으로 동작하는 것이 바람직합니다.

덧붙여, Cargo는 기능이 추가적(additive)이어야 한다고 요구하므로 no-abc처럼 부정형으로 이름 붙인 기능은 사실상 결코 올바르지 않습니다.

이름은 일관된 어순을 사용합니다 (C-WORD-ORDER)

다음은 표준 라이브러리에 있는 몇 가지 오류 타입입니다.

이들은 모두 동사-객체-오류 어순을 사용합니다. 주소 파싱 실패를 나타내는 오류를 추가한다면, 일관성을 위해 AddrParseError가 아니라 ParseAddrError처럼 동사-객체-오류 순서로 이름을 지어야 합니다.

어떤 어순을 선택하는지는 중요하지 않지만, 크레이트 내부의 일관성과 표준 라이브러리의 유사한 기능과의 일관성에 주의를 기울이십시오.