생성자

사용자 정의 타입의 값을 만드는 방법은 오직 하나입니다: 타입의 이름을 적고, 모든 필드들을 한번에 초기화하는 것입니다:

#![allow(unused)]
fn main() {
struct Foo {
    a: u8,
    b: u32,
    c: bool,
}

enum Bar {
    X(u32),
    Y(bool),
}

struct Unit;

let foo = Foo { a: 0, b: 1, c: false };
let bar = Bar::X(0);
let empty = Unit;
}

이게 전부입니다. 타입의 값을 만드는 다른 모든 방식은 다른 일을 좀 하고 결국에는 오직 진정한 하나의 생성자를 호출하는, 순수한 함수를 호출하는 것뿐입니다.

C++과 다르게, 러스트는 기본적으로 제공하는 다량의 생성자는 없습니다. 복사 생성자, 기본 생성자, 할당 생성자, 이동 생성자, 혹은 무슨 생성자든 없습니다. 이러는 이유는 여러 가지이지만, 가장 큰 이유는 러스트의 명시적으로 하자는 철학 때문입니다.

이동 생성자는 러스트에서는 의미가 없는데, 타입이 메모리의 위치에 대해서 "신경쓰는" 일이 없도록 하기 때문입니다. 모든 타입은 메모리의 다른 어딘가로 그냥 memcopy되도록 준비되어야 합니다. 이 뜻은 스택에는 있지만 이동 가능한, 불청객 링크드 리스트는 러스트에서는 존재하지 않는다는 뜻입니다 (안전하게 말이죠).

할당 생성자와 복사 생성자는 마찬가지로, 이동만이 러스트에서 가지는 의미이기 때문입니다. 거의 모든 x = y는 그냥 y의 비트들을 x 변수로 옮깁니다. 러스트는 C++의 복사하는 의미를 제공하기 위해 2개의 장치를 제공합니다: CopyClone이죠. Clone은 우리의 복사 생성자와 같은 기능을 하지만, 절대로 암시적으로 호출되지 않습니다. 복사를 원하는 값에 명시적으로 clone을 호출해야 하죠. CopyClone의 특수한 경우로, 그 구현은 그냥 "비트를 그대로 복사합니다". Copy 타입은 이동될 때 암시적으로 복사가 됩니다, 하지만 Copy의 정의 때문에 이 의미는 이전의 원본을 비초기화시키지 말라는 것이죠 -- 아무것도 하지 않는 작업입니다.

러스트가 기본 생성자의 기능을 Default 트레잇을 통해서 제공하지만, 이 트레잇이 사용되는 일은 매우 적습니다. 왜냐하면 변수는 암시적으로 초기화되지 않기 때문입니다. Default는 제네릭 프로그래밍에서야 유용합니다. 타입이 다 밝혀진 경우에서는, 그 타입이 "기본" 생성자를 new 정적 메서드를 통해 제공할 것입니다. 이것은 다른 언어에서의 new와 관계가 없고, 특별한 의미도 없습니다. 그냥 이름 짓는 관례일 뿐입니다.

TODO: talk about "placement new"?