Merge changes from master into SoonBin

SoonBin authored
revision 333e4111f6aa14cb9204f03c04032b38dfa79ce6
About
### Rust 문서 한글화 프로젝트

- 본 프로젝트는 Mozilla에서 개발한 Rust 언어의 문서를 한글화하는 프로젝트입니다.
- 현재 작업중인 문서는 [Book 1.2.0](http://doc.rust-lang.org/stable/book/) 이고, [Markdown](http://daringfireball.net/projects/markdown/basics) 포맷을 기본으로 합니다.
- 기본적인 문장체는 높임말로 끝나기만 하면 됩니다. 원문의 의도만 바뀌지 않는다면 재밌게 의역도 상관없습니다.
- 참여를 원하시는 분께서는 [sarojaba](mailto://sarojaba@gmail.com) 에게 연락주시기 바랍니다.
- 나중에 [rust](https://github.com/mozilla/rust) 프로젝트에 올릴 수 있을까요?
- 인터뷰: ['요즘 뜨는 4대 프로그래밍 언어, 이렇게 배워보세요.'](https://www.bloter.net/archives/230851)

- 최근 활발한 참여자
- [djKooks](https://www.penflip.com/djKooks)
- [handrake](https://www.penflip.com/handrake)
- [minujeong](https://www.penflip.com/minujeong)
- [jade.kim](https://www.penflip.com/jenix21)
- [jaeju_Kim](https://www.penflip.com/Jaeju_Kim)
- [SoonBin](https://www.penflip.com/SoonBin)

- 한글화 미완료 챕터 목록(작성중)
- [4.2. 테스팅 (Testing)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/testing.md) - 50%
- [4.3. 조건부 컴파일 (Conditional Compilation)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/conditional-compilation.md) - 30%
- [4.4. 문서화 (Documentation)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/documentation.md) - 15%
- [4.8. 외부 함수 인터페이스 (Foreign Function Interface)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/ffi.md) - 0%
- [4.9. Borrow and AsRef](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/borrow-and-asref.md) - 0%
- [5.2. 함수 (Functions)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/functions.md) - 50%
- [5.13. 열거형 (Enums)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/enums.md) - 0%
- [5.21. Drop](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/drop.md) - 0%
- [5.22. if let](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/if-let.md) - 0%
- [5.23. 트레잇 객체 (Trait Objects)](https://www.penflip.com/sarojaba/rust-doc-korean/blob/master/trait-objects.md) - 50%
strings
# 5.18. 문자열(Strings) - 8100%

문자열은 어느 프로그래머이든 마스터가 되기위한 중요한 개념입니다. Rust의 문자열 처리 시스템은 시스템 focus 때문에 다른 언어들과 좀 다릅니다. 언제라도 여러분은 다양한 크기의 자료 구조를 가집니다. 문자열은 약간 어려운 부분도 있지만, 크기 조절이 가능한 자료 구조입니다. 한마디로, Rust의 문자열 또한 C와 같은 다른 시스템 언어들과는 다르게 동작한다는 것입니다.

좀 더 자세히 파봅시다. ‘문자열(string)’은 UTF-8 바이트의 스트림으로 부호화된 유니코드 스칼라 값의 나열입니다. 모든 문자열은 올바르게 부호화된 UTF-8 나열이라는 것을 보장합니다. 게다가, 몇몇 시스템 언어들과 다르게 문자열은 null로 끝나지 않고 null 바이트를 포함할 수 있습니다.

Rust에는 두가지 주요 문자열 타입이 있습니다: `&str` 과 `String` 입니다. 우선 `&str`에 대해 이야기 해볼까요? 이것들은 ‘문자열 슬라이스(string slice)’라고 부릅니다. 문자열 리터럴은 `&'static str` 타입을 가집니다:

```rust
let greeting = "Hello there."; // greeting: &'static str
```

이 문자열은 정적으로 할당되며, 이것이 의미하는 바는 이것이 컴파일된 프로그램 안에 저장되어 있고, 프로그램이 실행되는 내내 존재한다는 뜻입니다. `greeting` 바인딩은 정적으로 할당된 문자열에 대한 참조입니다. 문자열 슬라이스는 고정된 크기를 가지며, 변경될 수 없습니다.

반면에, `String`은 힙에 할당된 문자열입니다. 이 문자열은 크기가 커질 수 있고, UTF-8 인코딩임이 보장됩니다. `String`들은 일반적으로 문자열 슬라이스를 `to_string` 메쏘드를 사용해서 변환함으로써 만들어집니다.

```rust
let mut s = "Hello".to_string(); // mut s: String
println!("{}", s);

s.push_str(", world.");
println!("{}", s);
```

`String`을 강제적으로 `&str`로서 사용할 때는(coerce) 그 앞에 `&`을 붙입니다.

```rust
fn takes_slice(slice: &str) {
println!("Got: {}", slice);
}

fn main() {
let s = "Hello".to_string();
takes_slice(&s);
}
```

This 이러한 강제(coercion does not happen for functions that accept one of)은 `&str` 대신에 `&str`’s traits
instead of `&str`. For example, [`TcpStream::connect`][connect] has a parameter
of type `ToSocketAddrs`. A `&str` is okay but a `String` must be explicitly
converted using `&*`
중 하나를 받는 함수에 대해서는 발생하지 않습니다. 예로 [`TcpStream::connect`][connect]는 `ToSocketAddrs` type의 인자를 가집니다. `&str`는 인자로서 허용되나, `String`은 반드시 명시적으로 `&*`를 사용해서 변환해주어야 합니다.

```rust,no_run
use std::net::TcpStream;

TcpStream::connect("192.168.0.1:3000"); // &str parameter

let addr_string = "192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // convert addr_string to &str
```

`String`을 `&str`로서 다루는 것은 비용이 적지만, `&str`을 `String`로 변환하는 것은 메모리 할당을 필요로 합니다. 그럴 이유가 없다면 그렇게 하지 마시기를!

## 인덱싱

문자열들은 유효한 UTF-8로 인코딩되었기 때문에, 문자열들은 그 안의 문자들에 대해 인덱싱을 통한 접근을 지원하지 않습니다.

```rust,ignore
let s = "hello";

println!("The first letter of s is {}", s[0]); // ERROR!!!
```

일반적으로, `[]`을 통해 벡터에 접근하는 것은 아주 빠릅니다. 그러나, UTF-8로 인코딩된 문자열 안에 있는 각각의 문자들은 각각 서로 다른 길이의 바이트들로 이루어져 있기 때문에, 문자열 안의 n번째 문자를 찾기 위해서는 맨 처음부터 순서대로 탐색해 나가지 않으면 안됩니다. 이것은 상당히 비싼 동작이고, 우리는 이것이 오해를 불러 일으키기를 원치 않았습니다. 더욱이, '문자'가 정확히 무엇인지는 유니코드에서 제대로 정의되어 있지 않습니다. 우리는 문자열이 각각의 바이트들로서 보일 것인지, 혹은 codepoint로 보일 것인지 선택할 수 있습니다:

```rust
let hachiko = "忠犬ハチ公";

for b in hachiko.as_bytes() {
print!("{}, ", b);
}

println!("");

for c in hachiko.chars() {
print!("{}, ", c);
}

println!("");
```

이것은 다음을 출력합니다:

```text
229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172,
忠, 犬, ハ, チ, 公,
```

지금 보고 있는대로, `char`의 갯수보다는 많은 바이트(byte)들이 있습니다.

인덱스를 통한 참조와 비슷한 동작을 하고 싶다면 이렇게 하십시오:

```rust
# let hachiko = "忠犬ハチ公";
let dog = hachiko.chars().nth(1); // kinda like hachiko[1]
```

이것은 `chars`들의 전체 리스트를 살펴봐야 함을 강조해 줍니다.

## Slicing

You can get a slice of a string with slicing syntaxslicing 문법을 가지고 string의 slice를 얻을 수 있습니다.:

```rust
let dog = "hachiko";
let hachi = &dog[0..5];
```

But note that these are허나 이것들은 _byte_ offsets, not 이지 _character_ offsets. So
this will fail at runtime:
이 아닙니다. 그래서 위 코드는 compile-time에서는 문제가 없지만 runtime에서는 에러를 발생시킵니다.

```rust,should_panic
let dog = "忠犬ハチ公";
let hachi = &dog[0..2];
```

with this error다음과 같은 에러를 수반합니다:

```text
thread '
' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on
character boundary'
```

## 문자열 연결(Concatenation)

`String`에 대해, 그 뒤에 `&str`을 연결할 수 있습니다:

```rust
let hello = "Hello ".to_string();
let world = "world!";

let hello_world = hello + world;
```

그러나 두개의 `String`이 있을 땐, `&`가 필요합니다:

```rust
let hello = "Hello ".to_string();
let world = "world!".to_string();

let hello_world = hello + &world;
```

이것은 `&String`가 자동적으로 `&str`이 되도록 강제(coerce)되기 때문입니다. 이것은 ‘[`Deref` coercions][dc]’로 불리는 특징입니다.

[dc]: deref-coercions.html
[connect]: ../std/net/struct.TcpStream.html#method.connect
testing
# 4.2. 테스팅 (Testing) - 5100%

> 프로그램 테스팅은 버그의 존재를 보이는 매우 효과적인 방법일 수 있지만,
> 버그가 없다는 걸 보이는 데는 절망적으로 부적합하다.
>
> 에츠허르 W. 데이크스트라, "The Humble Programmer" (1972)

Rust 코드를 테스트하는 방법에 대해 이야기해봅시다. 여기에서는 Rust 코드를 테스트하는
올바른 방법에 대해서 얘기하지는 않을 것입니다. 어떻게 테스트를 작성하는 것이 옳고 그른가는
많은 의견들이 있지만, 이들 모두 같은 기본 도구를 쓰기 때문에, 여기에서는 이 도구를 쓰는
문법을 보여 주려고 합니다.

# `test` 속성

간단히 말해서, Rust에서 테스트는 `test` 속성이 표기된 함수입니다. Cargo를 써서 `adder`라는 이름의 새 프로젝트를 만들어 볼까요?

```bash
$ cargo new adder
$ cd adder
```

새 프로젝트를 만들면 Cargo는 자동으로 간단한 테스트를 생성해 줍니다.
다음은 `src/lib.rs`의 내용입니다.

```rust
#[test]
fn it_works() {
}
```

`#[test]`를 눈여겨 보세요. 이 속성은 이 함수가 테스트 함수임을 나타냅니다. 지금은
안에 아무 것도 없는데, 이러면 물론 테스트는 성공하겠죠! `cargo test`로 테스트를 돌릴 수
있습니다.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```

Cargo가 테스트를 컴파일하고 실행했습니다. 여기에는 두 종류의 출력이 있는데, 하나는
우리가 작성한 테스트에 해당하고, 다른 하나는 문서 테스트에 해당합니다. 문서 테스트에
대해서는 나중에 이야기할 것입니다. 우선은 이 줄을 보지요.

```text
test it_works ... ok
```

`it_works`는 우리가 짠 테스트 함수의 이름입니다.

```rust
fn it_works() {
# }
```

테스트 결과에 대한 요약도 볼 수 있습니다.

```text
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
```

그럼 왜 아무 것도 하지 않는 테스트가 성공하는 걸까요? `panic!`을 실행하지 않는 모든 테스트는
성공한 걸로 치고, `panic!`을 실행하는 테스트는 실패한 걸로 칩니다. 위 테스트가 실패하도록
만들어 봅시다.

```rust
#[test]
fn it_works() {
assert!(false);
}
```

`assert!`는 Rust가 제공하는 매크로로, 인자 하나를 받아서 그게 `true`면 아무 일도 하지 않고,
`false`면 `panic!`을 호출합니다. 한 번 테스트를 다시 돌려 보지요.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test it_works ... FAILED

failures:

---- it_works stdout ----
thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3



failures:
it_works

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

thread '
' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
```

Rust가 테스트가 실패했음을 알려 주었고...

```text
test it_works ... FAILED
```

결과 요약에도 반영되어 있네요.

```text
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
```

또한 이는 0이 아닌 상태 코드를 반환하는데...

```bash
$ echo $?
101
```

이 상태 코드는 `cargo test`를 다른 도구와 연동할 때 유용합니다.

테스트가 어떨 때 성공하고 어떨 때 실패하는지를 또 다른 속성으로 뒤집을 수 있습니다.
바로 `should_panic`입니다.

```rust
#[test]
#[should_panic]
fn it_works() {
assert!(false);
}
```

이제 이 테스트는 `panic!`을 호출하면 성공하고 그렇지 않고 끝까지 실행되면 실패합니다.
다시 실행해 보죠.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```

Rust는 `assert_eq!`라는 또 다른 매크로를 제공하는데, 이 매크로는 두 인자가 같은지 검사합니다.

```rust
#[test]
#[should_panic]
fn it_works() {
assert_eq!("Hello", "world");
}
```

이 테스트가 성공할까요 실패할까요? `should_panic` 속성이 있으므로, 이 테스트는 성공해야 합니다.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```

`should_panic` 테스트는 잘못 동작하기 쉬운데, 테스트가 미처 예상하지 못한 이유로
실패하지 않는다는 걸 보장하기 어렵기 때문입니다. 이를 피하기 위해 `should_panic` 속성에
`expected` 인자를 더할 수 있습니다. 이러면 실패 메시지에 지정한 텍스트가 들어 있을 때만
테스트가 성공할 것입니다. 위 예제를 다음과 같이 좀 더 안전하게 쓸 수 있습니다.

```rust
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
assert_eq!("Hello", "world");
}
```

기본적인 건 이걸로 되었으니, '진짜' 테스트를 작성해 보지요.

```rust,ignore
pub fn add_two(a: i32) -> i32 {
a + 2
}

#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
```

이와 같이, 알려진 인자로 함수를 호출한 뒤 예상되는 결과와 비교하는 건
`assert_eq!`를 쓰는 흔한 방법입니다.

# `tests` 모듈

우리가 위에서 작성한 예제 중에 자연스럽지 않은 부분이 하나 있는데, 그것은 `tests` 모듈을 빼먹은 것입니다. 우리가 작성한 예제를 자연스럽게 고치면 다음과 같습니다.

```rust,ignore
pub fn add_two(a: i32) -> i32 {
a + 2
}

#[cfg(test)]
mod tests {
use super::add_two;

#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
}
```

몇가지가 바뀌었는데, 첫번째는 `cfg` 속성과 함께 `mod tests`를 도입한 것입니다. 이 모듈은 모든 우리의 테스트들을 함께 묶는 것을 허용하며, 필요하다면 helper function들을 정의할 수 있도록 해주고, 이것들이 우리 크레이트의 일부분이 되지 않도록 해 줍니다. `cfg` 속성은 우리가 테스트를 진행할 때만 테스트 코드를 컴파일하도록 합니다. 이것은 컴파일하는 시간을 절약해주며, 우리의 테스트가 완전히 일반 빌드(normal build)에서 제외되는 것을 보장해 줍니다.

두번째 차이점은 `use` 선언입니다. 우리가 안쪽 모듈의 안에 있기 때문에, 우리는 우리가 테스트할 함수를 스코프(scope) 안으로 가져올 필요가 있습니다. 만약 큰 모듈에 대해서라면 모든 함수를 일일이 추가하는 것은 무척 짜증나는 작업이 될 것이고, 따라서 `glob` 기능을 사용할 필요가 있습니다. 이 기능을 사용하도록 `src/lib.rs`를 고쳐봅시다.

```rust,ignore

pub fn add_two(a: i32) -> i32 {
a + 2
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
}
```

`use`가 사용된 행을 확인해봅시다. '\*'가 보입니까? 이제 테스트를 해 봅시다.

```bash
$ cargo test
Updating registry `https://github.com/rust-lang/crates.io-index`
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```

잘 돌아갑니다!

현재의 관례상, `tests` 모듈은 자그마한 개별 기능을 시험하는 테스트들을 넣는데 주로
쓰입니다. 이른바 "유닛" 테스트인데요, 하지만 "통합" 테스트라면 어떻게 할까요?
`tests` 디렉토리는 바로 이 용도로 쓰입니다.

# `tests` 디렉토리

통합 테스트를 작성해 봅시다. 먼저 `tests` 디렉토리를 만들고, `tests/lib.rs` 파일을
안에 만들어서 내용을 이렇게 채웁니다.

```rust,ignore
extern crate adder;

#[test]
fn it_works() {
assert_eq!(4, adder::add_two(2));
}
```

지금껏 짰던 테스트와 비슷해 보이지만 조금 다른 게 있습니다. 맨 위에 `extern crate adder`가
들어간 게 보일 것입니다. `tests` 디렉토리 안에 있는 테스트들은 완전히 독립된 crate이므로,
우리가 짠 라이브러리를 테스트하려면 먼저 불러 들여야 합니다. 라이브러리를 쓰는 방법을 그대로
테스트하기 때문에 `tests`는 통합 테스트를 넣기에 좋은 장소입니다.

실행해 보지요.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Running target/lib-c18e7d3494509e74

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```

이제 출력이 세 개로 늘어났습니다. 원래 짰던 테스트는 그대로, 새 테스트가 추가되었습니다.

`tests` 디렉토리만 있으면 됩니다. 모든 것들이 tests에 집중되어 있기 때문에, `tests`는 여기에 필요치 않습니다.
That's all there is to the `tests` directory. The `tests` module isn't needed
here, since the whole thing is focused on tests.

이제 마지막으로 세번째 부분인 문서 테스트를 확인해 봅시다.
Let's finally check out that third section: documentation tests.

# 문서 테스트

문서와 예제보다 중요한 것은 없습니다. 문서가 쓰여진 이후에 코드가 변경되었기 때문에 작동하지 않는 예제보다 나쁜 것은 없습니다. 이런 상황을 방지하기 위해, 러스트는 당신의 문서에서 자동적으로 실행되는 예제를 지원합니다. 여기에 구체화돤 `src/lib.rs`가 예제와 함꼐 있습니다.

```rust,ignore
//! The `adder` crate provides functions that add numbers to other numbers.
//!
//! # Examples
//!
//! ```
//! assert_eq!(4, adder::add_two(2));
//! ```

/// This function adds two to its argument.
///
/// # Examples
///
/// ```
/// use adder::add_two;
///
/// assert_eq!(4, add_two(2));
/// ```
pub fn add_two(a: i32) -> i32 {
a + 2
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
assert_eq!(4, add_two(2));
}
}
```

모듈 레벨 문서인 `//!`와 함수 레벨 문서인 `///`를 주목하십시오. Rust의 문서 지원은 주석 안에 Markdown 문법을 사용하는 것을 지원하며, 따라서 세개의 역따옴표(grave)는 코드 블럭을 뜻합니다. 위의 코드와 같이, 그 아래에 예제를 붙여 `# Examples` 섹션을 첨가하는 것이 관습입니다.

테스트를 다시 한번 진행해 봅시다.

```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
Running target/adder-91b3e234d4ed382a

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Running target/lib-c18e7d3494509e74

running 1 test
test it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Doc-tests adder

running 2 tests
test add_two_0 ... ok
test _0 ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
```

이제 우리는 3종류의 테스트 전부를 다뤘습니다! 문서 테스트의 이름들을 확인해봅시다: `_0`는 모듈 테스트를 위해 생성된 것이고, `add_two_0`는 함수 테스트를 위한 것입니다. 여기에 붙은 순서는 `add_two_1`와 같이 당신이 예제를 붙여나감에 따라 자동적으로 증가할 것입니다.