Updated guessing-game.md

djKooks authored
revision 47b038074b1a7f5529dbc04ac4067a94f657ce8e
guessing-game
# 3.1. 추리 게임 (Guessing Game) - 100%

첫 프로젝트로 우리는 고전적인 초보자용 프로그래밍 문제인 추리 게임을 구현할 것입니다. 이 프로그램은 다음과 같이 동작합니다. 우리 프로그램은 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`와 비슷한 것이지만, 이것은 그 이후 생성된 실행 파일을 실행합니다. 시도이전 장에서 배운 `run` 명령어를 기억하시나요? 여기에서 다시 실행해 봅시다.

```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`해야 합니다. There is also a second ‘prelude’, the [`io` prelude][ioprelude], which serves a similar function: you import it, and it imports a number of useful, `io`-related things그리고 [`io` prelude][ioprelude] 라고 불리는 두번째 '서곡' 이 있는데, 이것을 임포트하면 `io`와 연관된 유용한 라이브러리들을 불러옵니다.

[prelude]: ../std/prelude/index.html
[ioprelude]: ../std/io/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)
.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
.expect("Failed to read line");
```

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

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

하지만 이러면 읽기가 어렵습니다. 그래서 우리는 세 개의 메서드 호출을 세 줄에 나누어 쓴 것입니다. 지금까지 앞에서 `read_line()`에 대해서 말했습니다. 그러나 대체 `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`을 사용했습니다. which Cargo understands to be any release that’s compatible with this specific version. Cargo는 버전 번호를 쓰는 표준적인 방법인 [의미적 버전 매기기][semver]를 이해합니다. 정확히 `0.3.0` 버전만 사용하고 싶다면, `=0.3.0`을 사용할 수 있습니다. 만약 최신 버전을 사용하고 싶다면 `*`를 이용할 수 있고, 사용할 버전의 범위를 적을 수도 있습니다. 더 자세한 정보를 위해서는 [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에게 중요한 힌트를 제공합니다.

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

`read_line()` 때처럼, `parse()` 메서드는 오류가 일어날 수 있습니다. 만약 문자열에 `A👍%` 같은 것들이 포함된다면 어떨까요? 숫자로 해석할 수 없겠죠. 때문에 우리는 `read_line()` 때 했던 일들을 해주어야 합니다. 오류 처리를 위한 `ok()` 와 `expect()` 말이에요 .

한번 실행해봅시다!

```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!
```

훌륭하네요! 제가 넣은 숫자 앞에 공백을 추가했는데도, 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!"),
}
}
}
```

다음과 같습니다. 그런데 잠깐, 무한 루프요? . `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!'
```

하! 숫자가 아닌 `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;
}
}
}
}
```

`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;
}
}
}
}
```

바뀐 라인은 다음과 같습니다:

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

`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!
```

멋집니다! 사소한 한 가지만 더 고친다면 추리 게임이 완성됩니다. 뭔지 아시겠나요? 그렇습니다. 우리의 비밀 숫자를 내보이고 싶지 않겠죠. 테스트에는 도움이 되었지만, 게임을 망치고 있습니다.
최종 완성본입니다:

```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;
}
}
}
}
```

# 완료!

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

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