Updated guessing-game.md

SoonBin authored
revision 87c21599be23b12b3b19b14d26c16b6f90bbb219
guessing-game
# 3.1. 추리 게임 (Guessing Game) - 40%

첫 프로젝트로 우리는 고전적인 초보자용 프로그래밍 문제인 추리 게임을 구현할 것입니다. 이 프로그램은 다음과 같이 동작합니다. 우리 프로그램은 1부터 100 사이의 정수형 난수를 생성합니다. 그리고 나서 우리에게 예측값을 입력받습니다. 우리에게 입력을 받은 프로그램은 그 값이 너무 작거나 너무 크면 우리에게 알려줍니다. 우리가 정확한 값을 예측하는 데 성공하면, 프로그램은 우리를 칭찬해 줄 것입니다. 괜찮죠?

# 구성

새 프로젝트를 구성해 봅시다. 여러분의 프로젝트 디렉터리에 가 주세요. `hello_world`를 위해서 디렉터리 구조와 `Cargo.toml`을 만들었던 방법을 기억하고 있으신가요? Cargo는 이 작업을 우리 대신 해 주는 명령어를 가지고 있습니다. 한번 보도록 합시다.


```bash
$ cd ~/projects
$ cargo new guessing_game --bin
$ cd guessing_game
```

우리는 `cargo new`에게 프로젝트의 이름과 함께 `--bin` 플래그를 넘겨주었습니다. 라이브러리가 아니라 바이너리를 만들고 있기 때문입니다.

생성된 `Cargo.toml`의 내용을 확인해 봅시다.

```toml
[package]

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

Cargo는 여러분의 환경으로부터 이 정보를 얻습니다. 만약 틀린 부분이 있다면 가서 고치세요.

마지막으로, Cargo는 우리를 위해서 'Hello, world' 프로그램을 작성해 두었습니다. `src/main.rs`를 확인해 보세요.

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

Cargo가 만들어 준 것을 컴파일해 봅시다.

```{bash}
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
```

훌륭하군요! 여러분의 `src/main.rs`를 다시 열어 봅니다. 우리는 이 파일에 모든 코드를 작성할 것입니다.

나아가기 전에, 또 다른 Cargo 명령어를 보여드리겠습니다. `run`입니다. `cargo run`은 `cargo build`와 비슷한 것이지만, 이것은 그 이후 생성된 실행 파일을 실행합니다. 시도해 봅시다.

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Hello, world!
```

좋군요! `run` 명령어는 여러분이 하나의 프로젝트를 빠르게 반복해야 할 때에 편리합니다. 우리 게임이 바로 그런 프로젝트이죠. 다음 것으로 넘어가기 전에 빠르게 각 반복을 테스트할 필요가 있습니다.


# 추측을 처리하기

시작해 봅시다! 추리 게임에서 처음으로 해야 할 것은 우리 플레이어들에게 예측값을 입력할 수 있도록 하는 것입니다. 이것을 여러분의 `src/main.rs` 에 넣으세요.

```rust,no_run
use std::io;

fn main() {
println!("Guess the number!");

println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");

println!("You guessed: {}", guess);
}
```

상당히 많군요! 조금씩 살펴보도록 합시다.

```rust,ignore
use std::io;
```

우리는 사용자 입력을 받고 결과를 출력해야 합니다. 그러므로 우리는 표준 라이브러리의 `io` 라이브러리가 필요합니다. Rust가 모든 프로그램에 임포트하는 것은 ['서곡'][prelude]이라 불리는 아주 작은 라이브러리 뿐입니다. 만약 서곡에 들어 있지 않은 것을 사용하고 싶다면, 여러분은 그것을 직접적으로 `use`해야 합니다.


[prelude]: ../std/prelude/index.html

```rust,ignore
fn main() {
```

이전에 보셨던 것처럼, `main()` 함수는 여러분의 프로그램으로 들어가는 진입점입니다. `fn` 문법은 새 함수를 선언하며, `()`는 매개 변수가 없다는 것을 나타냅니다. 그리고 `{`는 함수의 몸체를 시작합니다. 우리가 반환 타입을 포함시키지 않았기 때문에, 빈 [튜플][tuples]인 `()`으로 간주됩니다.


[tuples]: primitive-types.html#tuples

```rust,ignore
println!("Guess the number!");

println!("Please input your guess.");
```

우리는 `println!()`이 화면에 [문자열][strings]을 출력하는 [매크로][macros]라는 것을 이전에 배운 적이 있습니다.

[macros]: macros.html
[strings]: strings.html

```rust,ignore
let mut guess = String::new();
```

점점 흥미로워지고 있군요! 이 짧은 줄에 많은 것이 일어나고 있습니다. 첫 번째로 눈치챌 수 있는 것은, 이것은 '변수 결합'을 만드는 데 사용되는 [let 구문][let]이라는 것입니다. 이것들은 다음과 같은 형태를 취합니다.

```rust,ignore
let foo = bar;
```

[let]: variable-bindings.html

이것은 `foo`라는 이름의 새 결합을 만들고, 그것을 값 `bar`에 결합합니다. 많은 언어들에서 이것은 '변수'라고 불립니다만, Rust의 변수 결합은 몇 가지 특이한 점들을 가지고 있습니다.

예를 들어서, Rust의 변수들은 기본적으로 [변경 불가능][immutable]합니다. 그래서 우리는 이 예제에서 `mut`를 사용한 것입니다. 이것은 이 결합을 변경할 수 있도록 만듭니다. `let`은 좌변에 이름을 취하는 대신, 사실은 '[패턴][patterns]'을 받습니다. 우리는 더 나중에 패턴을 사용할 것입니다. 지금으로서는 충분히 사용할 수 있을 정도로 간단합니다.


```rust
let foo = 5; // immutable.
let mut bar = 5; // mutable
```

[immutable]: mutability.html
[patterns]: patterns.html

오, 그리고 `//` 은 그것이 있는 줄의 마지막까지를 주석으로 만듭니다. Rust는 [주석][comments] 속의 모든 내용을 무시합니다.

[comments]: comments.html

그러므로 지금 우리는 `let mut guess`가 이름이 `guess`인, 새 변경 가능한 결합을 도입한다는 것을 알고 있습니다. 그러나 거기에 결합될, 그 반대편에 있는 `String::new()`에 대해서도 보아야겠죠.


`String`은 표준 라이브러리에서 제공하는 문자열 타입입니다. [`String`][string]은 자라날 수 있는 UTF-8 텍스트입니다.


[string]: ../std/string/struct.String.html

`::new()` 문법에서 `::`를 사용하는 이유는 이것이 어떤 특정한 타입과 '연결된 함수'이기 때문입니다. 이것은 다시 말해서 new() 함수가 `String`의 인스턴스 하나하나에 연결되는 것이 아니라, `String` 그 자체에 연결되어 있다는 것을 말합니다. 일부 언어들은 이것을 '정적 메서드'라고 부릅니다.

이 함수는 빈 `String`을 새로 만들기 때문에 `new()`라는 이름을 가지고 있습니다. 어떤 종류의 새로운 값을 만드는 데 흔하게 사용되는 이름이기 때문에, 여러분은 많은 타입들에서 `new()` 함수를 보게 될 것입니다.


다시 진행해 봅시다.

```rust,ignore
io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");
```

아주 많은 것이 있군요! 하나하나씩 봅시다. 첫 번째 줄은 두 부분으로 이루어져 있습니다. 다음이 첫 번째 부분입니다.

```rust,ignore
io::stdin()
```

프로그램의 첫 줄에서 `std::io`를 `use` 했던 것을 기억하고 있습니까? 이제 우리는 거기에 연결된 함수들을 호출합니다. 만약 우리가 `use std::io`를 하지 않았다면, 우리는 이 줄을 `std::io::stdin()`으로 쓸 수도 있었습니다.

이 특별한 함수는 여러분의 터미널의 표준 입력에 대한 핸들을 반환합니다. 더 자세히 알고 싶으면 [std::io::Stdin][iostdin]을 참고하세요.

[iostdin]: ../std/io/struct.Stdin.html

다음 부분은 이 핸들을 사용자로부터 입력을 받는 데 사용할 것입니다.

```rust,ignore
.read_line(&mut guess)
```

여기에서 핸들에게 [`read_line()`][read_line] 메서드를 호출합니다. [메서드][method]는 연결된 함수와 비슷하지만, 그 타입 자체가 아니라 그 타입의 각 인스턴스들에서만 사용할 수 있습니다. 우리는 또한 `read_line`에 매개변수 하나(`&mut guess`)를 넘기고 있습니다.

[read_line]: ../std/io/struct.Stdin.html#method.read_line
[method]: method-syntax.html

위에서 `guess`를 어떻게 결합하는지 기억하고 계신가요? 우리는 이게 변경 가능하다고 말했었습니다. 그러나, `read_line`은 `String`을 매개변수로 취하지 않고, 대신 `&mut String`을 취합니다. Rust는 '[참조][references]'라고 부르는 기능을 가지고 있습니다. 이 기능은 하나의 데이터 조각에 대해 여러 개의 참조를 가질 수 있도록 해서, 복사 회수를 줄일 수 있습니다. Rust의 주요 특장점 중 하나가 레퍼런스를 쉽고 안전하게 사용할 수 있다는 점인 것처럼, 참조는 복잡한 기능입니다. 그러나 우리 프로그램을 마치기 위해서 자세한 내용들을 알아야 할 필요는 없습니다. 지금으로서는, 우리가 알아야 할 것은 `let` 결합처럼, 참조는 기본적으로 변경 불가능하다는 것입니다. 따라서, 우리는 `&guess` 대신 `&mut guess`를 써야 합니다.

`read_line()`이 문자열에 대한 변경할 수 있는 참조를 취하는 이유는 무엇일까요? 이 함수의 역할은 사용자가 표준 입력에 넣은 것을 가져다가 문자열 안쪽에 놓는 것입니다. 따라서 이 함수는 문자열을 매개변수로 받아서 거기에 입력을 더해야 하므로 참조는 변경 가능해야 합니다.


[references]: references-and-borrowing.html

그러나 아직도 이 코드에서 보아야 할 것이 남아 있습니다. 단 한 줄으로 이뤄져 있지만, 이 코드에 담긴 논리의 첫 부분에 지나지 않습니다.

```rust,ignore
.ok()
.expect("Failed to read line");
```

`.foo()` 문법으로 메서드를 호출하려고 할 때, 여러분은 새 줄을 만들거나 다른 공백 문자를 사용하게 될지도 모릅니다. 이렇게 함으로써 길이가 아주 긴 코드를 여러 개로 나눌 수 있습니다. 우리는 다음과 같이 _할 수도_ 있었습니다.

```rust,ignore
io::stdin().read_line(&mut guess).ok().expect("failed to read line");
```

하지만 이러면 읽기가 어렵습니다. 그래서 우리는 세 개의 메서드 호출을 세 줄에 나누어 쓴 것입니다. 지금까지 앞에서 `read_line()`에 대해서 말했습니다. 그러나 대체 `ok()`와 `expect()`는 뭘까요? 뭐, 우리는 `read_line()`이 사용자의 입력을 우리가 넘긴 `&mut String`에 넣는다고 했었습니다. 그러나 이 함수도 값을 하나 반환합니다. 이 경우에 반환값은 [`io::Result`][ioresult]가 됩니다. Rust의 표준 라이브러리에는 `Result`라는 이름의 타입이 여럿 있는데, 일반적인 버전의 [`Result`][result]와 `io::Result` 같은 종속 라이브러리들에 대한 특화된 버전들이 있습니다.

[ioresult]: ../std/io/type.Result.html
[result]: ../std/result/enum.Result.html

이러한 `Result` 타입들의 목적은 오류 처리 정보를 기록하는 것입니다. 여느 타입들과 마찬가지로 `Result` 타입의 값들은 그 타입에 대해 정의된 메서드를 가지고 있습니다. 예컨대 `io::Result`에는 `ok()` 메서드가 있습니다. 이 메서드가 말하고자 하는 바는 '나는 이 값이 성공적인 것이라고 가정하려 한다'는 뜻입니다. 만약 그렇지 않다면, 이 메서드는 오류 정보를 그냥 던져버립니다. 어째서 던져버리냐고요? 뭐, 기초적인 프로그램이기 때문에 그냥 일반적인 오류를 출력하고 싶거든요. 어떠한 문제든 기본적으로는 더 진행할 수가 없다는 것을 의미하기 때문입니다. 이 [`ok()` 메서드][ok]는 또 다른 메서드 `expect()`가 정의된 다른 값을 반환합니다. 이 [`expect()` 메서드][expect]는 자신이 호출된 값이 성공적인 것이 아니라면, 여러분이 넘긴 메시지를 가지고 [`panic!`][panic]을 호출합니다. 이런 `panic!`은 우리가 만든 프로그램이 메시지를 출력하고 나서 기능을 멈추도록 만듭니다.


[ok]: ../std/result/enum.Result.html#method.ok
[expect]: ../std/option/enum.Option.html#method.expect
[panic]: error-handling.html

만약 이 두 개의 메서드를 떼어낸다면, 우리 프로그램은 컴파일이 되겠지만 다음과 같은 경고가 나오게 됩니다.

```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:10:5: 10:39 warning: unused result which must be used,
#[warn(unused_must_use)] on by default
src/main.rs:10 io::stdin().read_line(&mut guess);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

Rust가 우리에게 사용되지 않은 `Result` 값이 있다고 경고합니다. 이 경고는 `io::Result`가 가지고 있는 특별한 참고용 주석_annotation_으로부터 왔습니다. Rust는 발생할 수 있지만 여러분이 처리하지 않은 에러에 대해 말하려고 시도합니다. 이러한 오류를 숨기기 위한 올바른 방법은 실제로 에러 처리 코드를 작성하는 것입니다. 다행히도 문제가 있을 때 그냥 동작을 멈추고 싶다면 위의 두 메서드를 사용하면 됩니다. 만약 어떤 방식으로든 오류로부터 복구하고 싶다면 다른 무언가를 하게 될 테지만, 그것은 나중의 프로젝트로 미루도록 하겠습니다.

이제 첫 예제의 마지막 줄이 남았습니다.

```rust,ignore
println!("You guessed: {}", guess);
}
```

우리가 입력을 저장했던 문자열을 출력합니다. `{}`는 자리 표시자입니다. 그리고 우리는 거기에 `guess`를 매개 변수로 넘깁니다. 혹시 여러 개의 `{}`가 있다면, 다음처럼 여러 개의 매개 변수를 넘기게 될 것입니다.

```rust
let x = 5;
let y = 10;

println!("x and y: {} and {}", x, y);
```

쉽군요.

어쨌든 그렇습니다. `cargo run`을 통해 지금까지 한 것을 실행할 수 있습니다.

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
6
You guessed: 6
```

좋습니다! 이제 첫 번째 부분은 끝났습니다. 이제 우리는 키보드로부터 입력을 받고, 그걸 다시 출력할 수 있습니다.


# 숨김수 생성하기

이제 우리는 숨김수를 만들어야 합니다. Rust는 아직 표준 라이브러리에 난수 기능을 포함하고 있지 않습니다. 그러나 Rust 팀은 [`rand` 크레이트][randcrate]를 제공합니다. '크레이트'는 Rust 코드의 패키지입니다. 우리는 지금까지 실행 가능한 '바이너리 크레이트'를 만들고 있었습니다. 반면에 `rand`는 '라이브러리 크레이트'입니다. 라이브러리 크레이트는 다른 프로그램들이 사용하도록 의도된 코드들을 담고 있습니다.

[randcrate]: https://crates.io/crates/rand

외부 크레이트를 사용할 때야말로 Cargo가 빛을 보는 때입니다. 우리가 `rand`를 쓰는 코드를 작성하기 전에, `Cargo.toml`을 수정해야 합니다. 다음 몇 줄을 파일의 뒤에 추가하세요.

```toml
[dependencies]

rand="0.3.0"
```

`Cargo.toml` 파일의 `[dependencies]` 절은 `[package]` 절과 비슷합니다. 다음 절이 시작하기 전까지 등장하는 것들이 그 일부분입니다. Cargo는 외부 크레이트에 대한 의존성 여부와 필요한 버전을 알기 위해 dependencies 절을 사용합니다. 이 경우 우리는 `0.3.0`을 사용했습니다. Cargo는 버전 번호를 쓰는 표준적인 방법인 [의미적 버전 매기기][semver]를 이해합니다. 만약 최신 버전을 사용하고 싶다면 `*`를 이용할 수 있고, 사용할 버전의 범위를 적을 수도 있습니다. 더 자세한 정보를 위해서는 [Cargo 문서][cargodoc]을 보시기 바랍니다.

[semver]: http://semver.org
[cargodoc]: http://doc.crates.io/crates-io.html

이제 우리 프로젝트를 빌드해 봅시다.

```bash
$ cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading rand v0.3.8
Downloading libc v0.1.6
Compiling libc v0.1.6
Compiling rand v0.3.8
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
```

(물론 다른 버전을 보실 수도 있습니다.)

새로운 출력이 많군요! 이제 우리는 외부 의존성을 가지고 있고, Cargo는 [Crates.io][cratesio] 데이터의 사본인 레지스트리로부터 최신 버전들을 가져옵니다. Crates.io는 Rust 생태계에 속한 사람들이 자신들의 오픈 소스 프로젝트를 다른 이들이 사용할 수 있도록 올리는 곳입니다.

[cratesio]: https://crates.io

레지스트리를 업데이트한 다음, Cargo는 우리 `[dependencies]`를 확인하고, 아직 가지고 있지 않은 것들을 내려받습니다. 지금 우리는 `rand`에만 의존하고 싶다고 말했지만 `libc`의 사본 또한 가져왔습니다. 그 이유는 `rand`의 동작이 `libc`에 의존하기 때문입니다. Cargo는 이들을 내려받아 컴파일하고, 다음으로 우리 프로젝트를 컴파일합니다.

`cargo build`를 다시 실행하면, 이번에는 다른 출력을 얻습니다.

```bash
$ cargo build
```

맞습니다. 출력이 없군요! Cargo는 우리 프로젝트가 이미 빌드되었고, 프로젝트가 의존하고 있는 모든 것이 빌드되어 있음을 알고 있습니다. 따라서 그것들을 다시 수행할 이유가 없고, 이제 할 것이 없으므로 그냥 종료합니다. 만약 `src/main.rs`를 다시 열어서 약간 수정하고 다시 저장한다면 다음 한 줄을 보게 될 것입니다.

```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
```

우리는 Cargo에게 `rand`의 `0.3.x`버전이라면 뭐든지 좋다고 말했으므로, Cargo는 이 글이 쓰이는 시점에서 최신 버전인 `v0.3.8`을 가져옵니다. 그러나 만약 중요한 버그 수정을 위해 다음 주에 `v0.3.9`가 나온다면 어떻게 될까요? 버그 수정은 중요하지만, 만약 `0.3.9`가 우리 코드를 깨지게 만드는 수정 내용을 가지고 있다면 어떨까요?

이 문제의 답은 `Cargo.lock` 파일입니다. 이 파일은 여러분의 프로젝트 디렉터리에서 찾을 수 있습니다. 프로젝트를 처음 빌드할 때 Cargo는 여러분의 조건에 맞는 모든 버전을 계산하고, 그것을 `Cargo.lock` 파일에 적습니다. 나중에 여러분의 프로젝트를 다시 빌드하면, Cargo는 `Cargo.lock` 파일이 존재하는 것을 보고, 새로 버전을 확인하기보다는 거기에 적혀 있는 버전을 사용합니다. 이로 인해 여러분은 자동적으로 빌드를 반복할 수 있습니다. 무슨 말이냐면, lock 파일 덕분에 우리는 명시적으로 업그레이드하기 전까지는 `0.3.8` 버전에 머무른다는 말이죠. 그리고 우리 코드를 공유하는 다른 모든 사람들 또한 그렇습니다.

`v0.3.9`를 사용하고 싶다면 어떻게 _해야_ 할까요? Cargo는 `update`라는 또 다른 명령어를 갖고 있습니다. 이것은 'lock을 무시하고, 우리가 명세한 것에 들어맞는 최신 버전을 찾아내어, 있다면 lock 파일에 그 버전을 기록하라'는 의미입니다. 그렇지만 Cargo는 기본적으로 `0.3.0`보다 크고 `0.4.0`보다 작은 버전만을 찾습니다. 만약 `0.4.x`로 옮기고 싶다면, 우리는 `Cargo.toml`을 직접 수정해야 할 것입니다. 그렇게 한 후에 `Cargo build`를 실행하면, Cargo는 우리의 `rand` 요구사항을 다시 평가하여 색인을 갱신할 것입니다.

[Cargo][doccargo]와 [그 생태계][doccratesio]에 대해서는 할 말이 많지만, 지금 필요한 것은 모두 설명했습니다. Cargo는 라이브러리 재사용을 매우 쉽게 만들기 때문에, Rust인들은 많은 부패키지를 조립한 작은 프로젝트를 작성하는 경향이 있습니다.

[doccargo]: http://doc.crates.io
[doccratesio]: http://doc.crates.io/crates-io.html

이제 실제로 `rand`를 _사용해_ 봅시다.

```rust,ignore
extern crate rand;

use std::io;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

println!("You guessed: {}", guess);
}
```

가장 먼저 첫 번째 줄을 바꿨습니다. 이제 `extern crate rand` 라고 되어 있군요. 우리의 `[dependencies]`에 `rand`를 선언했기 때문에, Rust에게 우리가 이것을 사용하겠다고 알리기 위해 `extern crate`를 사용할 수 있습니다. 이 명령은 동시에 `use rand`와 같은 역할을 수행하기 때문에, 우리는 `rand` 크레이트 내부의 어떤 것이든 `rand::`라는 접두어를 붙여 사용할 수 있습니다.

다음으로, 우리는 또 다른 `use` 라인을 추가했습니다. 그 내용은 `use rand::Rng`입니다. 어떤 메서드 하나를 잠시 사용할 건데, 이 메서드는 `Rng`가 스코프 내에 있어야 사용할 수 있습니다. 기본적인 아이디어는 이것입니다. 메서드들은 '특성'이라고 불리는 무언가 위에 정의됩니다. 그리고 이 메서드가 동작하기 위해서는, 그 특성이 스코프 내에 있어야 합니다. 더 자세한 내용이 필요하면 [특성][traits] 절을 읽어 주세요.


[traits]: traits.html

중간쯤에 우리가 추가한 또 다른 두 줄이 있습니다.

```rust,ignore
let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);
```

난수 발생기의 사본을 하나 얻기 위해 `rand::thread_rng()` 함수를 사용했습니다. 이 난수 발생기는 우리가 현재 실행하고 있는 특정한 [스레드][concurrency]에 대해 하나씩 존재합니다. 위에서 `use rand::Rng`를 적었기 때문에, `gen_range()` 메서드를 사용할 수 있습니다. 이 메서드는 두 개의 인자를 받아서, 그 사이의 수를 생성합니다. 이 메서드는 하한값은 포함하지만, 상한값은 포함하지 않습니다. 따라서 우리는 1부터 100 사이의 수를 생성하기 위해 `1`과 `101`을 사용해야 합니다.

[concurrency]: concurrency.html

두 번째 줄은 단지 비밀수를 출력합니다. 이 부분은 프로그램을 개발하는 동안 테스트하기가 쉬워지기 때문에 쓸모가 있습니다. 그러나, 최종본에서는 이 부분을 삭제할 것입니다. 시작할 때 답을 출력해 버리면 게임이 되지 않으니까요!

새 프로그램을 몇 번 시험해 봅시다.

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 7
Please input your guess.
4
You guessed: 4
$ cargo run
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 83
Please input your guess.
5
You guessed: 5
```

잘 되는군요! 다음으로는 우리의 추측과 비밀수를 비교해 봅시다.

# 추측 비교하기

이제 사용자의 입력을 받았으니, 우리의 추측을 난수와 비교해 봅시다. 다음이 그 단계이지만, 아직 잘 작동하지는 않습니다.

```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
```

새로운 것들이 약간 들어가 있군요. 그 첫번째는 또 다른 `use`입니다. `std::cmp::Ordering`이라는 타입 하나를 스코프 안으로 가져왔습니다. 그 다음은 아래쪽에서 그걸 사용하고 있는 다섯 줄의 새 라인입니다.

```rust,ignore
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
```

`cmp()` 메서드는 비교될 수 있는 모든 것에서 호출이 가능합니다. 그리고 이 메서드는 여러분이 비교하고자 하는 어떤 것의 레퍼런스를 취합니다. 또 이 메서드는 우리가 앞에서 `use`한 `Ordering` 타입을 반환합니다. 우리는 `Ordering` 중에서 정확히 어떤 것인지를 확실히 알아내기 위해서 [`match`][match] 구문을 사용합니다. `Ordering`은 [`enum`][enum]입니다. 그리고 enum은 열거형(enumeration)의 준말이고, 다음과 같이 생겼습니다.

```rust
enum Foo {
Bar,
Baz,
}
```

[match]: match.html
[enum]: enums.html

이 정의에서, `Foo` 타임의 어떤 것은 `Foo::Bar` 또는 `Foo::Baz`가 될 수 있습니다. `::`는 특정한 `enum` 변형을 위한 네임스페이스를 나타내는 용도입니다.

[`Ordering`][ordering] enum은 `Less`와 `Equal`, `Greater`의 세 가지 변형을 가지고 있습니다. `match` 구문은 어떤 타입의 어떤 값을 취해서, 가능한 값들 각각에 대해서 '가지'를 만들도록 합니다. 세 가지 종류의 `Ordering`이 있기 때문에, 가지도 세 갈래입니다.

```rust,ignore
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
```

[ordering]: ../std/cmp/enum.Ordering.html

만약 `Less`라면 우리는 `Too small!`을 출력합니다. 만약 `Greater`라면 `Too big`을 출력합니다. 그리고 `Equal`일 때는 `You win`을 출력합니다. `match`는 정말로 유용하며 Rust에서 자주 사용합니다.

그렇지만 아직 잘 동작하지 않는다고 언급했었죠. 시험해 봅시다.

```bash
$ cargo build
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
src/main.rs:28:21: 28:35 error: mismatched types:
expected `&collections::string::String`,
found `&_`
(expected struct `collections::string::String`,
found integral variable) [E0308]
src/main.rs:28 match guess.cmp(&secret_number) {
^~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `guessing_game`.
```

휴! 큰 에러입니다. 핵심적인 것은 우리가 '타입 불일치(mismatched types)'를 갖고 있다는 점입니다. Rust는 강력한 정적 타입 시스템을 가지고 있습니다. 하지만 Rust는 동시에 타입 추론 기능도 가지고 있습니다. 우리가 `let guess = String::new()`라고 썼을 때, Rust는 `guess`가 반드시 `String`이 되어야 한다는 것을 추론해낼 수 있습니다. 그래서 Rust는 우리에게 타입을 적으라고 하지 않습니다. 그리고 우리의 `secret_number`에 대해서, 1부터 100까지의 수를 저장할 수 있는 타입은 여러 개 존재합니다. 32비트 수인 `i32`나, 부호 없는 32비트 정수형인 `u32`나, 64비트 정수형인 `i64` 등이 있죠. 여기까지는 별로 문제가 없습니다. 그래서 Rust는 기본적으로 `i32`를 사용합니다. 그러나 여기서, Rust는 어떻게 `guess`와 `secret number`를 비교할 수 있는지 알지 못합니다. 그들은 서로 같은 타입이어야 합니다. 궁극적으로는, 입력으로 읽어들인 `String`을 실제 수 타입으로 변환해야만 서로 비교할 수 있습니다. 다음의 세 줄을 추가하여 그렇게 할 수 있습니다.


```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
```

새로 추가한 세 줄은 다음과 같습니다.

```rust,ignore
let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");
```

잠깐, 우리 이미 `guess`를 갖고 있지 않았나요? 그랬습니다. 하지만 Rust는 새 `guess`로 이전 것을 '가리기'를 허용합니다. 이 기능은 `guess`가 `String`으로 시작했지만, 그것을 `u32`로 변경하고 싶은 바로 이러한 상황에 자주 사용됩니다. 가리기 기능 덕분에 우리는 `guess_str`과 `guess`같은 서로 겹치지 않는 이름을 지어내는 대신, `guess`라는 이름을 다시 사용할 수 있습니다.


우리는 `guess`를 이전에 썼던 뭔가와 비슷한 표현식에 결합합니다.

```rust,ignore
guess.trim().parse()
```

`ok().expect()`의 호출에 이어, 여기서의 `guess`는 이전에 인풋으로 받았던 `String`을 저장해둔 `guess`를 참조합니다. `String`의 `trim()` 메서드는 앞, 뒤의 모든 띄어쓰기 및 빈칸을 제거합니다.
이것이 중요한 이유는, 우리가 `read_line()`을 만족시키기 위해 'return' 키를 눌렀기 때문입니다. 만약 우리가 `5`를 입력하고 'return'을 누르면, `guess`의 값이 `5¶
`이 된다는 뜻입니다. `¶
`은 '다음 줄'(Enter키)을 의미합니다. `trim()`을 실행해서 이것을 제거해주고, 우리가 입력한 `5`를 그대로 남겨줍니다. [문자열의 `parse()` 메서드][parse]는 문자열을 일종의 숫자로 해석해줍니다. 이것은 여러 가지 타입의 숫자로 해석할 수 있기 때문에, 우리는 Rust에게 우리가 원하는 정확한 타입에 대한 힌트를 줄 필요가 있습니다. 이렇게요: `let guess: u32`. `guess` 뒤의 콜론(`:`)은 Rust에게 중요한 힌트를 제공합니다.
The [`parse()` method on
strings][parse] parses a string into some kind of number. Since it can parse a
variety of numbers, we need to give Rust a hint as to the exact type of number
we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust
we’re going to annotate its type. `u32` is an unsigned, thirty-two bit
integer. Rust has [a number of built-in number types][number], but we’ve
chosen `u32`. It’s a good default choice for a small positive number.

[parse]: ../std/primitive.str.html#method.parse
[number]: primitive-types.html#numeric-types

Just like `read_line()`, our call to `parse()` could cause an error. What if
our string contained `A👍%`? There’d be no way to convert that to a number. As
such, we’ll do the same thing we did with `read_line()`: use the
때처럼, `parse()` 메서드는 오류가 일어날 수 있습니다. 만약 문자열에 `A👍%` 같은 것들이 포함된다면 어떨까요? 숫자로 해석할 수 없겠죠. 때문에 우리는 `read_line()` 때 했던 일들을 해주어야 합니다. 오류 처리를 위한 `ok()` and
`expect()` methods to crash if there’s an error.

Let’s try our program out
말이에요 .

한번 실행해봅시다
!

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 58
Please input your guess.
76
You guessed: 76
Too big!
```

Nice! You can see I even added spaces before my guess, and it still figured
out that I guessed 76. Run the program a few times, and verify that guessing
the number works, as well as guessing a number too small.

Now we’ve got most of the game working, but we can only make one guess. Let’s
change that by adding loops!

# Looping

The `loop` keyword gives us an infinite loop. Let’s add that in
훌륭하네요! 제가 넣은 숫자 앞에 공백을 추가했는데도, 76으로 잘 처리하고 있습니다. 프로그램을 몇 번 실행해보고, 여러가지 숫자들을 넣어 시험해보세요.

게임 동작의 대부분을 완성했지만, 아직 한 가지 일이 남아있습니다.
`loop`를 추가해보도록 하죠!

# 루핑

`loop` 키워드는 무한 루프를 제공합니다. 사용해보면
:

```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

loop {
println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
}
```

And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember
our discussion about `parse()`? If we give a non-number answer, we’ll `return`
and quit. Observe
다음과 같습니다. 그런데 잠깐, 무한 루프요? . `parse()`에서 했던 말들 기억나시나요?
숫자가 아닌 추측들이 주어지면, 에러 처리로 인해 우린 곧바로 프로그램이 `return` 되고 종료됩니다.
직접 보여드리죠
:

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 59
Please input your guess.
45
You guessed: 45
Too small!
Please input your guess.
60
You guessed: 60
Too big!
Please input your guess.
59
You guessed: 59
You win!
Please input your guess.
quit
thread '
' panicked at 'Please type a number!'
```

Ha! `quit` actually quits. As does any other non-number input. Well, this is
suboptimal to say the least. First, let’s actually quit when you win the game
하! 숫자가 아닌 `quit` 입력이 말 그대로 프로그램을 종료시켰군요.
이것은 단지 일부일 뿐입니다. 첫째로, 우리가 추측을 성공시켰을 때도 게임을 종료해야하죠
:

```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

loop {
println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

let guess: u32 = guess.trim().parse()
.ok()
.expect("Please type a number!");

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
```

By adding the `break` line after the `You win!`, we’ll exit the loop when we
win. Exiting the loop also means exiting the program, since it’s the last
thing in `main()`. We have just one more tweak to make: when someone inputs a
non-number, we don’t want to quit, we just want to ignore it. We can do that
like this
`break`를 `You win!` 줄 아래에 추가함으로써, 추측이 성공했을 때 루프를 탈출할 수 있게 됩니다.
루프가 돌고 있다는 것은 `main()` 이 남아있어 프로그램이 계속 존재한다는 것을 뜻합니다.
하나만 더 해보죠. 누군가가 숫자가 아닌 추측을 입력했을 때 종료하는 대신 그냥 그것을 무시하고 싶습니다.
이렇게 할 수 있겠죠
:

```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

println!("The secret number is: {}", secret_number);

loop {
println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
```

These are the lines that changed바뀐 라인은 다음과 같습니다:

```rust,ignore
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
```

This is how you generally move from ‘crash on error’ to ‘actually handle the
error’, by switching from `ok().expect()` to a `match` statement. The `Result`
returned by `parse()` is an enum just like `Ordering`, but in this case, each
variant has some data associated with it: `Ok` is a success, and `Err` is a
failure. Each contains more information: the successful parsed integer, or an
error type. In this case, we `match` on `Ok(num)`, which sets the inner value
of the `Ok` to the name `num`, and then we just return it on the right-hand
side. In the `Err` case, we don’t care what kind of error it is, so we just
use `_` instead of a name. This ignores the error, and `continue` causes us
to go to the next iteration of the `loop`.

Now we should be good! Let’s try
`ok().expect()` 를 `match` 문으로 전환하면서, 우리는 단순한 '충돌 방지' 에서'실질적 에러 핸들'이 가능하게 되었습니다. `parse()`에 의해 리턴된 `Result`는 `Ordering` 때와 같이 열거형입니다. 그러나 이번 경우엔, 각 라인이 관련이 있는 어떤 정보들을 지니고 있습니다: `Ok`는 성공, `Err`는 실패를 나타내죠. 더 구체적으로, 숫자라면 성공적, 다른 타입이라면 에러입니다. `match` 안의 `Ok(num)`은 `Ok`의 내부 값을 `num`이라는 이름에 담습니다. 그런 다음 곧바로 그것을 우변에서 리턴합니다. `Err`의 경우 어떤 종류의 에러이든지 상관하지 않을 때 이름 대신 `_`를 쓸 수 있습니다. 에러를 무시하고, `continue`를 실행해 다음 `loop`로 건너뛸 수 있게 해줍니다.

제대로 작동할 것 같네요! 실행시키면
:

```bash
$ cargo run
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 61
Please input your guess.
10
You guessed: 10
Too small!
Please input your guess.
99
You guessed: 99
Too big!
Please input your guess.
foo
Please input your guess.
61
You guessed: 61
You win!
```

Awesome! With one tiny last tweak, we have finished the guessing game. Can you
think of what it is? That’s right, we don’t want to print out the secret
number. It was good for testing, but it kind of ruins the game. Here’s our
final source
멋집니다! 사소한 한 가지만 더 고친다면 추리 게임이 완성됩니다. 뭔지 아시겠나요? 그렇습니다. 우리의 비밀 숫자를 내보이고 싶지 않겠죠. 테스트에는 도움이 되었지만, 게임을 망치고 있습니다.
최종 완성본입니다
:

```rust,ignore
extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1, 101);

loop {
println!("Please input your guess.");

let mut guess = String::new();

io::stdin().read_line(&mut guess)
.ok()
.expect("failed to read line");

let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
```

# Complete!

At this point, you have successfully built the Guessing Game! Congratulations!

This first project showed you a lot: `let`, `match`, methods, associated
functions, using external crates, and more. Our next project will show off
even more
완료!

추리 게임을 성공적으로 만들었습니다! 축하드립니다!

이 첫 번째 프로젝트는 많은 것을 다루었습니다: `let`, `match`, 메소드, 연결된 함수, 외부 크레이트 사용하기 등등. 다음 프로젝트에서는 더 많은 것을 다룰 것입니다
.