Updated readme.md

nyeong authored
revision 17384040a39aea874f9100b3df51eb5b68195883
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_ 등 연관된 모든 문제점들을 예방하는데에 유용합니다.