Merge changes from Compiztab into master

sarojaba authored
revision 784fb2f029eb68972d9e32e0a7491ab0dcb28c7f
Contents
About.txt
readme.md
getting-started.md
installing-rust.md
hello-world.md
hello-cargo.md
learn-rust.md
guessing-game.md
dining-philosophers.md
rust-inside-other-languages.md
effective-rust.md
the-stack-and-the-heap.md
testing.md
conditional-compilation.md
documentation.md
iterators.md
concurrency.md
error-handling.md
choosing-your-guarantees.md
ffi.md
borrow-and-asref.md
release-channels.md
syntax-and-semantics.md
variable-bindings.md
functions.md
primitive-types.md
comments.md
if.md
loops.md
for-loops.md
while-loops.md
ownership.md
references-and-borrowing.md
lifetimes.md
mutability.md
structs.md
enums.md
match.md
patterns.md
method-syntax.md
vectors.md
strings.md
generics.md
traits.md
drop.md
advanced-linking.md
if-let.md
trait-objects.md
closures.md
ufcs.md
crates-and-modules.md
concordance.md
hello-cargo
# 2.3. 안녕, 카고! (Hello, Cargo!) - 100%

[Cargo][cratesio]는 러스트인(Rustaceans)들에게 그들의 Rust 프로젝트 관리를 도와주는 도구입니다. Cargo는 pre-1.0 상태이고, 그렇기 때문에 아직 개발중입니다. 하지만, 이미 많은 Rust 프로젝트에 사용하기에 충분히 좋기 때문에, Rust 프로젝트를 시작할때 Cargo를 사용할 것이라고 가정합니다.

[cratesio]: http://doc.crates.io

Cargo는 세가지를 관리합니다. 여러분의 코드를 빌드하고, 여러분의 코드가 필요로하는 종속성(dependencies)들을 다운로드하고, 그 종속성들을 빌드합니다. 처음에는, 여러분의 프로그램은 어떠한 종속성도 갖지 않기 때문에, 우리는 오직 이 놈의 기능의 첫번째 부분만 사용합니다. 결과적으로 우리는 더(종속성등을) 추가할것입니다. Cargo를 사용하기 시작했기에 이러한 작업은 더욱 쉬워질것입니다.

여러분이 Rust를 공식 인스톨러를 통해 설치했다면, Cargo 또한 가지고 있을 것입니다. Rust를 몇몇 다른 방식으로 설치했다면, 설치에 관한 좀더 자세한 사항은 [check the Cargo README][cargoreadme]를 참고하세요.

[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies

## Cargo로 변환하기 (Converting to Cargo)

Hello World를 Cargo로 변환해 봅시다.

여러분의 프로젝트를 Cargo화(-ify) 하려면, 두 가지가 필요합니다. `Cargo.toml` 설정 파일을 만들고, 소스 파일을 적당한 위치에 가져다 둡니다. 시작해 볼까요?

```bash
$ mkdir src
$ mv main.rs src/main.rs
```

실행파일을 생성할것이기에 `main.rs`를 사용했습니다. 만약 여러분이 라이브러리를 생성하고 싶으시면 `lib.rs`를 사용해야합니다. 이 관습은 Cargo가 우리의 프로젝트를 성공적으로 컴파일하는데 필요로 하지만, 원한다면 overridden 할 수 있습니다. 프로그램 엔트리를 사용자 파일로 하시고자 하신다면 TOML파일의 [`[lib]` or `[[bin]]`][crates-custom] 섹션에 설정하실수 있습니다.

[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target

Cargo는 여러분의 소스 파일들이 `src` 디렉토리에 있을거라고 생각합니다. 그 외에 README, 라이선스 정보, 코드와 관련 없는 것들은 최상위에 두셔도 됩니다. Cargo는 여러분의 프로젝트를 깔끔하게 유지하는데 도움을 줍니다. 여기에 프로젝트의 모든 것이 위치합니다.

이어서, 설정 파일을 보겠습니다.

```bash
$ editor Cargo.toml
```

이름에 유의하세요! 대문자 `C` 이어야 합니다.

다음을 입력하세요.

```toml
[package]

name = "hello_world"
version = "0.0.1"
authors = [ "Your name " ]
```

이 파일은 [TOML][toml] 형식으로 작성되었습니다. TOML은 INI와 비슷하지만, 몇몇 추가적인 장점들을 가지고 있습니다. TOML 문서를 살펴보면,

> TOML은 명백한 의미 덕분에 쉽게 읽을 수 있는 최소한의 설정 파일 형식을 지향합니다. TOML은 해쉬테이블로 매칭이 명확하게되도록 디자인되어있습니다.
> TOML은 다양한 언어의 데이터구조로 쉽게 변환될수 있습니다.

[toml]: https://github.com/toml-lang/toml

파일이 제대로 설정되었다면 우리는 이제 빌드를 할 준비가 되었습니다! 실행해봅시다.

```bash
$ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/debug/hello_world
Hello, world!
```

짜잔! 여러분들은 `cargo build`를 통해 프로젝트를 빌드했고, `./target/debug/hello_world`로 실행했습니다. `cargo run`으로 한번에 할 수도 있습니다.

```bash
$ cargo run
Running `target/debug/hello_world`
Hello, world!
```

우리는 이 프로젝트를 재빌드하지 않았음에 주목해주세요. Cargo는 우리가 소스파일에 어떠한 수정도 하지 않았음을 자동적으로 인식하고, 빌드 없이 바이너리를 실행했습니다. 만약 우리가 수정을 했다면 재빌드와 실행의 두가지 결과를 보게될것입니다.

```bash
$ cargo run
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
Running `target/debug/hello_world`
Hello, world!
```

이것은 우리에게 `rustc`를 단순하게 사용하는 것 이상을 가져다 주진 않지만, 나중을 생각해봅시다. 우리 프로젝트가 더 복잡해진다면, 프로젝트의 모든 부분이 정상적으로 컴파일되기 위해서 더 많은 작업을 해야 할 것입니다. Cargo를 이용한다면 프로젝트가 커지더라도, 단지 `cargo build`를 실행하는 것만으로도 올바르게 동작할 것입니다.

여러분의 프로젝트를 배포할 준비가 다 되었다면, `cargo build --release` 커맨드를 이용하여 여러분의 프로젝트를 컴파일하고 최적화할수 있습니다.

추가로, Cargo가 `Cargo.lock`라는 새로운 파일을 생성한다는 것을 알 수 있을 것입니다.

```toml
[root]
name = "hello_world"
version = "0.0.1"
```

`Cargo.lock` 파일은 Cargo에서 여러분의 애플리케이션의 종속성을 추적하는데 사용됩니다. 현재 우리는 아무런 종속성을 가지고 있지 않기 때문에 많은 내용이 없습니다. 여러분은 이 파일을 건드릴 필요가 없으며, Cargo에서 처리하도록 놔두면 됩니다.

끝입니다! 우리들은 Cargo를 이용해 `hello_world`를 성공적으로 빌드했습니다. 이번 프로그램은 단순하지만, 앞으로의 Rust 개발 경력에 있어 실제로 자주 사용하게 될 도구들을 사용하고 있습니다. 앞으로 대부분의 Rust 프로젝트들을 이와 같은 과정으로 시작하게 될 것입니다.

```bash
$ git clone someurl.com/foo
$ cd foo
$ cargo build
```

## 새 프로젝트(A New Project)

새로운 프로젝트를 시작하기 위해 매번 모든 절차를 진행해야 하지 마세요! Cargo는 여러분이 즉시 개발을 시작하도록 프로젝트 디렉토리의 기본 골격을 만드는 능력을 가지고 있습니다.

Cargo를 이용해 새 프로젝트를 시작하려면, `cargo new`를 이용하세요.

```bash
$ cargo new hello_world --bin
```

우리의 목적은 라이브러리와는 다르게 실행할 수 있는 응용 프로그램을 곧바로 얻기 위함이기 때문에 `--bin`을 전달했습니다. 실행 가능한 것들은 주로 ‘바이너리(binaries).’라고합니다. (유닉스 시스템이라면 `/usr/bin`에 있는 것들이죠.)

Cargo가 무엇을 만들었는지 확인해볼까요?

```bash
$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
└── main.rs

1 directory, 2 files
```

`tree` 명령어가 없다면, 배포판 패키지 관리자에서 받을 수 있습니다. 꼭 필요한 것은 아니지만, 확실히 도움은 됩니다.

이것이 시작하기에 필요한 전부입니다. 우선, `Cargo.toml`을 확인해봅시다.

```toml
[package]

name = "hello_world"
version = "0.1.0"
authors = ["Your Name "]
```

Cargo는 여러분이 넘겨주는 인자들과 `git`의 전역 설정을 토대로 합당한 기본값으로 이 파일을 생성합니다. 그리고 `hello_world` 디렉토리를 `git` 레파지터리로 초기화합니다.

`src/main.rs`을 살펴봅시다.

```rust
fn main() {
println!("Hello, world!");
}
```

Cargo는 여러분을 위해 "Hello World!"를 생성했고, 여러분은 코딩을 시작할 준비가 되었습니다. Cargo는 더 세부적인 기능을 다루고 있는 [가이드][guide]를 자체적으로 가지고 있습니다.

[guide]: http://doc.crates.io/guide.html

이제 필요한 툴을 다 갖췄으면 Rust 언어에 대해 더 배워볼 시간입니다. 이런 기본들은 여러분이 Rust와 함께 하는 시간동안 많은 도움을 줄 것입니다.

두 가지 선택이 있습니다: 곧바로 ‘[Rust 배우기][learnrust]’로 프로젝트에 뛰어들거나 ‘[문법과 의미][syntax]’를 통해 밑바닥부터 배울 수도 있습니다. 경험이 풍부한 시스템 프로그래머는 아마 ‘Rust 배우기’ 쪽이, 동적 언어 세계에서 오신 분들은 어느 쪽이나 상관없을 테지요. 각자 자기 방식대로 배우는 겁니다! 여러분에게 맞는 쪽을 택하세요.

[learnrust]: learn-rust.htmlmd
[syntax]: syntax-and-semantics.htmlmd
readme
# 1. 소개(Introduction) - 100%

환영합니다! 이 책은 당신에게 [Rust 프로그래밍 언어][rust]에 대해 알려줄 것입니다. Rust는 세가지 목표(안전성, 속도, 병행성)에 초점을 맞춘 시스템 프로그래밍 언어입니다. Rust는 가비지 콜렉터 없이 이러한 목표를 달성하고 있고, 때문에 다른 언어들이 그다지 훌륭하지 못한 몇 가지 부분에서 강세를 보입니다. 예를 들어 다른 언어에 내장(_embedding_)시키는 일, 특정한 공간/시간 제약을 갖는 프로그램을 작성하는 일, 장치 드라이버나 운영 체제 등의 로우 레벨 코드를 작성하는 일 등이죠. Rust는 컴파일 타임에 이루어지는 몇 가지 안정성 체크를 통해 런타임 오버헤드를 발생시키지 않으면서도 이러한 목표를 가진 현존하는 언어들보다 뛰어난 성과를 보여줍니다. 또한, Rust는 고수준 언어들이 제공하는 것과 비슷하게 느껴지는 추상화를 제공하면서도 '무비용 추상화_zero-cost abstraction_'을 달성하고자 합니다. 그러면서도, 많은 로우 레벨 언어들처럼 정밀한 제어도 가능케 하죠.

[rust]: http://rust-lang.org

“Rust 프로그래밍 언어”는 여덟 단원으로 구분됩니다. 이 소개는 그 중 첫번째고, 나머지는 다음과 같습니다.

* [시작하기(Getting started)][gs] - Rust 개발을 위한 컴퓨터 환경 구축.
* [Rust 배우기(Learn Rust)][lr] - 작은 프로젝트를 통한 Rust 프로그래밍의 학습.
* [효과적인 Rust(Effective Rust)][er] - 훌륭한 Rust 코드를 작성하기 위한 더 높은 수준의 개념들.
* [문법과 의미(Syntax and Semantics)][ss] - 조그만 조각들로 쪼개서 살펴보는 Rust의 세세한 부분들.
* [실험적 Rust(Nightly Rust)][nr] - 아직 안정적인 빌드에 포함되지 않은 최신 기능들.
* [용어 해설(Glossary)][gl] - 책에서 사용된 용어들의 참조.
* [학문적 연구(Academic Research)][ar] - Rust에 영향을 준 문헌.

[gs]: getting-started.md
[lr]: learn-rust.md
[er]: effective-rust.md
[ss]: syntax-and-semantics.md
[nr]: nightly-rust.md
[gl]: glossary.md
[ar]: academic-research.md

이 글을 읽은 후, 'Rust 배우기'나 '문법과 의미' 둘 중 하나로 넘어가길 추천드립니다. 프로젝트를 하나 붙잡고 집중하고 싶다면 'Rust 배우기'를, 다음으로 넘어가기 전에 개념을 하나씩 완전히 익히는 것을 선호하신다면 '문법과 의미'를 선택하면 됩니다. 이 두 부분 사이엔 많은 다리들이 연결되어 있지요.

### 기여

이 책을 생성하는 원본 파일들은 Github에서 찾을 수 있습니다.
[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl)

## Rust에 대한 간략한 소개

Rust는 당신이 흥미를 가질 만한 언어일까요? Rust의 장점 몇 가지를 보여주기 위해 짧은 예제 코드 몇 개를 살펴보죠.

Rust를 다른 어떤 언어와도 다른 것으로 만드는 주요 개념은 바로 '소유권'이라고 합니다. 다음 짧은 예제를 한 번 보죠.

```rust
fn main() {
let mut x = vec!["Hello", "world"];
}
```

이 프로그램은 `x`라는 이름의 [변수 바인딩][var]을 생성합니다. 이 바인딩의 값은 `Vec` 또는 '벡터'입니다. 우리는 이것을 표준 라이브러리에 정의되어 있는 [매크로][macro]를 통해서 만들었습니다. 이 매크로는 `vec`이라고 하는데, 모든 매크로는 `!`과 함께 실행됩니다. 이것은 Rust의 기본 원칙 중 하나를 따른 것입니다. "모든 것을 명시적으로 만들어라." 함수에 비교했을 때 매크로는 훨씬 더 복잡한 작업들을 할 수 있고, 따라서 둘은 외형적으로 구분됩니다. 또한 `!`은 파싱 과정을 도우며, 중요한 도구들을 작성하기 쉽도록 해 줍니다. 역시 중요한 점이죠.

우리는 `mut`를 사용해서 `x`를 변경 가능한 변수_mutable variable_로 만들었습니다. Rust에서는 변수 바인딩은 기본적으로 변경할 수 없습니다_immutable_. 우리는 나중에 이 벡터를 변경하는 예제도 살펴보죠.

타입을 명시적으로 기술하지 않았다는 것도 주목할만한 점이죠. Rust는 정적 타입 언어지만, 타입을 꼭 명시적으로 적을 필요가 없습니다. 정적 타이핑의 강력함과 타입을 장황하게 적어야 하는 불편함 사이에서 균형을 잡기 위해, Rust는 타입 추론(type inference) 기능을 가지고 있습니다.

Rust는 힙 할당보다 스택 할당을 선호합니다. `x`는 스택 위에 바로 할당됩니다. 그러나, `Vec` 타입은 벡터의 요소들을 저장하기 위한 공간을 힙에 할당합니다. 만약 무슨 차이인지 모르겠다면, 일단 여기에서는 무시해도 좋습니다. 아니면 [‘스택과 힙’][heap] 문서를 참고하셔도 좋구요. 시스템 프로그래밍 언어로서 Rust는 메모리를 어떻게 할당할 것인가에 대한 제어권을 사용자에게 제공합니다. 그러나 우리는 이제 막 시작하는 참이고, 이게 그렇게 중요한 일은 아니겠죠.

[var]: variable-bindings.md
[macro]: macros.md
[heap]: the-stack-and-the-heap.md

앞서 '소유권'이 Rust의 새로운 주요 개념이라고 언급한 바 있습니다. Rust 어법에서, `x`는 그 벡터를 '소유합니다'. 이는 `x`가 유효 범위(Scope)의 바깥으로 나갈 때, 그 벡터의 메모리가 해제된다는 것을 의미합니다. Rust 컴파일러는 이 과정을 쓰레기 수집(Garbage collection) 등의 방법을 통하지 않고 결정론적으로 수행합니다. 다른 말로 설명하면, Rust에서 여러분은 `malloc`이나 `free` 같은 함수를 직접 호출하지 않습니다. 컴파일러는 어느 시점에 메모리를 할당하고 해제해야 하는지를 정적으로 결정하고, 그런 호출을 스스로 집어넣습니다. 인간은 실수하는 동물이지만, 컴파일러는 절대 까먹지 않습니다.

우리 예제에 다른 한 줄을 추가해 봅시다.

```rust
fn main() {
let mut x = vec!["Hello", "world"];

let y = &x[0];
}
```

우리는 또 다른 바인딩 `y`를 도입했습니다. 여기에서 `y`는 벡터의 첫 번째 요소를 가리키는 '참조' 입니다. Rust의 참조는 다른 언어들의 포인터와 비슷하지만, 컴파일 시간에 수행되는 추가적인 안전성 검사를 가지고 있습니다. 참조들은 그들이 가리키는 것을 소유하는 대신 [‘빌림’][borrowing]으로써 소유권 시스템과 소통합니다. 참조는 유효 범위 바깥으로 나가더라도 자신이 가리키고 있던 메모리를 해제하지 않는다는 차이점을 가지고 있습니다. 만약 그렇지 않았다면 같은 메모리에 대한 두 번의 해제가 일어나겠죠. 그게 영 좋지 않은 일이란건 명백하구요!
[borrowing]: references-and-borrowing.md

세 번째 줄을 추가해 봅시다. 겉보기에는 별 문제 없어 보이는 코드입니다만, 이는 컴파일러 오류를 유발합니다.

```rust,ignore
fn main() {
let mut x = vec!["Hello", "world"];

let y = &x[0];

x.push("foo");
}
```
`push`는 벡터의 메서드로 또 다른 요소 하나를 벡터의 끝에 추가합니다. 이 프로그램을 컴파일하려 시도하면 다음과 같은 오류를 얻게 됩니다.

```text
error: cannot borrow `x` as mutable because it is also borrowed as immutable
x.push("foo");
^
note: previous borrow of `x` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `x` until the borrow ends
let y = &x[0];
^
note: previous borrow ends here
fn main() {

}
^
```

휴! 때때로 Rust 컴파일러는 오류에 대해 상당히 자세히 알려줍니다. 그리고 이번이 바로 그런 때로군요. 오류 메시지에 따르면, 우리가 변수 바인딩을 변경할 수 있도록 만들음에도 불구하고 여전히 `push`를 호출할 수 없습니다. 이것은 우리가 벡터의 한 요소를 가리키는 참조 `y`를 이미 가지고 있기 때문입니다. 다른 참조가 가리키고 있는 무엇인가를 변경하는 것은, 우리가 그 참조를 무효화할 수도 있기 때문에 위험한 행동입니다. 이 경우를 구체적으로 살펴보면, 벡터를 생성할 때, 딱 두 개의 요소를 담을 수 있는 메모리만이 할당되었을 수도 있겠죠. 여기에 세 번째 요소를 추가한다는 것은 세 요소를 모두를 담을 수 있는 메모리 공간을 새롭게 할당하고, 기존 값들을 복사하고, 그 메모리를 가리키도록 내부 포인터를 업데이트하는 것을 의미합니다. 이러한 일련의 동작은 별 문제없이 작동합니다. 문제는 그 과정에서 `y`는 업데이트되지 않고, 따라서 '댕글링 포인터_dangling pointer_'를 갖게 된다는 것입니다. 좋지 않죠. 이 경우 `y`를 어떤 방식으로든 사용한다면 에러가 날 것이므로, 컴파일러가 우리를 위해서 잡아준 것입니다.

어떻게 이 문제를 해결할 수 있을까요? 두 가지 접근법을 취할 수 있습니다. 첫 번째 방법은 참조를 사용하는 대신 복제본을 만드는 것입니다.

```rust
fn main() {
let mut x = vec!["Hello", "world"];

let y = x[0].clone();

x.push("foo");
}
```

Rust는 기본적으로 [move semantics][move]을 따릅니다. 따라서 만약 어떤 데이터의 복제본을 만들고 싶다면, `clone()` 메소드를 호출합니다. 이 예제에서, `y`는 더 이상 `x`에 저장된 벡터를 가리키는 참조가 아니고, 그 첫 번째 요소의 복제본인 `"Hello"`입니다. 이제 참조가 존재하지 않으므로, `push()`는 잘 동작하겠죠.

[move]: ownership.htmlmd#move-semantics

만약 정말로 참조를 사용하고 싶다면, 또 다른 선택지가 필요합니다. 어떤 참조에 대한 변경이 시행되기 전에 반드시 그것이 유효 범위를 벗어나도록 만드는거죠. 다음과 같이 말입니다.


```rust
fn main() {
let mut x = vec!["Hello", "world"];

{
let y = &x[0];
}

x.push("foo");
}
```

우리는 추가적인 중괄호 쌍을 이용해 안쪽에 새로운 유효 범위를 만들었습니다. `y`는 우리가 `push()` 를 호출하기 전에 유효 범위를 벗어날 것이므로 문제는 발생하지 않겠죠.


이렇듯 소유권 시스템은 단지 댕글링 포인터뿐만 아니라, 반복자 무효화_iterator invalidation_, 동시성_concurrency_ 등 연관된 모든 문제점들을 예방하는데에 유용합니다.