#1 동작하는 프로그램 만들어보기

Pt J·2020년 8월 11일
1

[完] Rust Programming

목록 보기
2/41
post-thumbnail

이 시리즈는 Rust 공식문서를 통해 공부한 흔적임을 밝힙니다.

Hello, world!를 출력하는 것만으로는 Rust 프로그래밍을 해봤다고 하기 애매하다.
따라서 우리는 유의미하게 동작하는 프로그램을 직접 작성해보며
Rust 프로그래밍을 간단히 맛보는 시간을 갖도록 하겠다.

단순히 맛보기일 뿐이며, 아직 배우지 않은 내용을 다루고 있으므로
모든 것을 이해하고 넘어가려고 하기 보다는
Rust 프로젝트의 전체적인 구성을 훑어본다는 느낌으로 나아가자.프로젝트-관리
코드에 대한 설명이 주를 이루어 매우 길어 보이겠지만 겁먹지 말자.
이건 단지 호기심을 불러일으키고 동기부여를 하는 내용이다.

우리는 이 시간에 숫자 맛히기 게임을 구현할 것이다.

숫자 맛히기 게임 Guessing Game

  • 1과 100 사이의 임의의 정수, 난수값을 생성한다.
  • 플레이어가 어떤 값을 예상했는지 묻고 플레이어는 예측값을 입력한다.
  • 플레이어의 예측값과 생성된 난수값을 비교하여 비교 결과를 알려준다.
  • 플레이어의 예측값이 생성된 난수값과 일치하면 축하 메시지를 출력 후 종료한다.

⚠️ 본 게시물의 예제는 오래된 버전의 코드를 포함합니다!
게시물 작성 시점의 rand 크레이트의 최신 버전은 0.7.3 으로,
다음과 같이 난수를 생성했던 반면,
let secret_number = rand::thread_rng().gen_range(1, 101);
2021년 7월 12일 기준 rand 크레이트의 최신 버전은 0.8.4 으로,
다음과 같이 난수를 생성하도록 변경되었습니다.
let secret_number = rand::thread_rng().gen_range(1..101);
이를 제보해주신 fregataa 님께 감사드리며,
본 게시물을 보고 실습을 따라하고자 하시는 분은 최신 버전의 rand 크레이트 사용 시
rand::thread_rng().gen_range 함수의 인자를 변경하여 진행해주시기 바랍니다.
― 2021.07.15 Edited

guessing_game 프로젝트

먼저, Cargo를 통해 새 프로젝트를 생성해야 한다.
숫자 맛히기 게임이니까 guessing_game이라는 이름을 사용하겠다.

peter@hp-laptop:~/rust-practice$ mkdir chapter02
peter@hp-laptop:~/rust-practice$ cd chapter02
peter@hp-laptop:~/rust-practice/chapter02$ cargo new guessing_game
     Created binary (application) `guessing_game` package
peter@hp-laptop:~/rust-practice/chapter02$ cd guessing_game
peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

지난 시간에도 살펴봤듯이, Cargo.tomlsrc/main.rs가 자동 생성되었다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
peter@hp-laptop:~/rust-practice/chapter02/guessing-game$ 

우리의 코드는 이 자동 생성된 src/main.rs에 작성될 것이다.
한 번에 모든 것을 작성하기 보다는 조금씩 확장적으로 구현하도록 하겠다.

예측값 처리

먼저, 플레이어가 어떤 값을 예상했는지 묻고
플레이어는 예측값을 입력한다.
에 해당하는 부분을 작성해보자.
src/main.rs에 자동 생성된 코드를 지우고 다음과 같이 작성하면 된다.
// 당장은 이해를 못하더라도 따라 적어보는 것을 추천한다.

~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
        .expect("Fail to read line");
   
    println!("You guessed: {}", guess);
}

이 코드를 차근차근 해석해보자.
사용자의 입력을 받기 위해서는 표준 입력 함수가 필요한데
이것은 표준 라이브러리 std의 입출력 라이브러리 io에서 가져올 수 있다.
맨 첫번째 줄의 use std::io;는 이를 위한 코드다.
Prelude에 포함되어 있는 자료형은 그냥 사용할 수 있지만
그렇지 않은 것들은 use를 통해 가져와야 한다.

Prelude
모든 Rust 프로그램이 자동으로 가져오는 것들의 목록.
Rust는 모든 crate의 root에 extern crate std;을 추가하고
모든 module에 use std::prelude::v1::*;을 추가한다.
// crate과 module에 대한 건 일단 그런 게 있구나 하고 넘어가자.
std::prelude::v1에 무엇이 들어있는지 궁금하다면 문서를 참고하자.

다음으로 보게 되는 것은 main 함수인데,
fn 키워드를 통해 함수를 선언할 수 있다는 것과 {}에 본문이 들어간다는 것은 지난 시간에 이야기했다.
소괄호 ()의 경우 매개변수가 존재한다면 그 안에 들어가지만
우리의 main 함수는 매개변수를 가지지 않아 비워두었다.

println!이 문자열 출력을 위한 매크로라는 것도 지난 시간에 다루었으니 자세한 설명은 생략한다.

다음으로 우리는 let mut guess = String::new();를 통해
변수를 저장하기 위한 공간을 마련한다.
Rust에서 변수는 let 키워드를 통해 선언한다.
Rust의 변수는 기본적으로 불변성을 가지고 있으며
mut 키워드로 가변성을 명시해주어야 그 값을 변경할 수 있는데
이에 대한 설명은 추후에 진행하겠다.
단지 우리 예제에서는 값의 변경이 필요해 mut 키워드를 사용했다는 것 정도만 알고 넘어가자.
=는 우측값을 좌측값에 bind하겠다는 의미인데
guess 변수에 String::new 함수의 반환값을 bind한다는 것이다.
String은 Prelude에 포함되어 있는, 표준 라이브러리가 제공하는 문자열 자료형이다.
이것은 길이 조절이 가능하며 UTF-8 형식으로 인코딩된 텍스트를 표현한다.
newString 자료형에 구현되어 있는 함수로, 이런 함수를 연관 함수라고 부른다.
연관 함수에 대한 것도 나중에 다룰테니 일단 빈 문자열을 생성해서 guess에 bind했다는 것만 이해하자.

이제 io로 시작하는 조금 길어보이는 코드를 마주했다.
io는 Prelude에 포함되어 있지 않아 우리가 use를 통해 가져왔던 녀석이다.
그리고 stdin은 방금 본 String::new와 마찬가지로 io의 연관 함수다.
사실 use를 사용하지 않고 std::io::stdin으로 사용할 수도 있지만
그럴 경우 코드가 복잡해질 수 있다는 건 여담.
io::stdin는 터미널로부터 표준 입력을 받는 핸들의 인스턴스를 반환한다.
그리고 표준 입력 핸들의 메서드 read_line을 통해 사용자가 입력한 값을 얻어올 수 있다.
얻어온 값은 read_line의 인자로 전달된 변수에 저장된다.
read_line에 의해 변경되기 때문에 그것의 인자는 가변성을 가지고 있어야 한다.
이것이 우리가 guess 변수에 가변성을 부여한 이유다.
&는 값을 복사하지 않고 접근하기 위한 참조에 이용되며
참조는 기본적으로 불변성을 띄기 때문에 가변성을 갖고 참조하겠다는 의미에서
&mut guess와 같이 인자를 전달한다.
나중에 더 자세히 배우겠지만 불변성을 띈 변수는 가변 참조가 안된다는 것은 여담.

io::std::Stdin의 메서드 read_lineio::Result 자료형의 값을 반환한다.
io::Result는 열거형으로, OkErr 두 가지 값을 가지고 있다.
작업이 성공적으로 완료되면 Ok가 반환되며, 이것은 성공적으로 생성된 값을 가진다.
그렇지 않을 경우 Err가 반환되며, 이것은 실패 원인에 대한 정보를 가진다.
이 녀석은 보통 예외처리를 하기 위해 사용된다.
io::Result의 메서드 expect는 그 인자값이 Ok인지 Err인지에 따라
Ok라면 그것이 가진 성공적으로 생성된 값을 반환하고
Err라면 프로그램을 종료하고 인자로 전달된 메시지를 출력한다.
우리 예제에서는 성공 시 표준 입력으로 입력된 문자열의 바이트 수를 반환하지만 사용하지 않는다.
Result를 반환할 때 이것에 대한 예외처리를 해주지 않으면
컴파일은 되지만 이에 대한 경고가 출력될 것이다.

마지막으로, println! 매크로를 다시 만났는데 이 녀석은 지금까지 봤던 녀석들과 조금 다르다.
문자열에 {}가 존재하며 문자열 외에 우리가 선언한 변수 guess도 인자로 전달되었다.
{}는 자리지정자placeholder로, 어떤 값이 들어갈 자리를 의미하며,
그곳에 들어갈 값은 문자열 뒤에 ,를 사이에 두고 전달하면 된다.
자리지정자를 여러 개 사용할 경우 그 순서에 맞게 ,를 사이에 두고 열거하면 된다.

우리가 작성한 코드를 전체적으로 이해했으니 이제 한 번 실행해보자.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
78
You guessed: 78

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

Please input your guess.가 출력되면 우리가 어떤 값을 입력할 때까지 대기할 것이고
우리가 어떤 값을 입력하면 마저 실행된다.

난수 생성

이번에는 1과 100 사이의 임의의 정수,
난수값을 생성한다.
에 해당하는 부분을 작성해보자.
난수 생성은 Rust의 표준 라이브러리에서는 지원하지 않지만
Rust 팀이 제공하는 rand 크레이트를 사용하면 이러한 기능을 사용할 수 있다.
크레이트crate는 라이브러리 또는 바이너리 소스 파일의 집합이라고만 알아두자.
안에 들어 있는 소스 코드를 가져다 쓸 수 있는 라이브러리 크레이트와
main 함수가 있어 실행 가능한 바이너리 크레이트가 존재하는데
rand 크레이트는 라이브러리 크레이트에 해당한다.
우리가 작성하고 있는 guessing_game도 크레이트다, 바이너리 크레이트.

rand 크레이트와 같은 외부 크레이트를 사용하려면
Cargo.toml에 그것을 의존 패키지로 등록해주어야 한다.
Cargo.toml[dependencies] 아래에 의존 패키지를 추가할 수 있다.
의존 패키지 이름과 그것의 시멘틱 버전을 입력한다.

~/rust-practice/chapter02/guessing_game$ vi Cargo.toml

Cargo.toml

[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Peter J <peter.j@kakao.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.7.3"

이제 이 프로젝트에서는 rand 크레이트 0.7.3 버전을 사용할 수 있다.
이 상태로 cargo build를 수행하면 rand 크레이트에 필요한 것들이
0.7.3 버전과 호환되는 버전으로 다운로드된다.
Cargo는 현재 프로젝트에 아직 다운로드 되지 않은 것만 다운로드하므로
최초에 한 번만 다운로드 할 것이다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo build
   Compiling autocfg v0.1.7
   Compiling rand_core v0.4.2
   Compiling libc v0.2.74
   Compiling rand_core v0.3.1
   Compiling rand_jitter v0.1.4
   Compiling rand_hc v0.1.0
   Compiling rand_xorshift v0.1.1
   Compiling rand_isaac v0.1.1
   Compiling rand_chacha v0.1.1
   Compiling rand_pcg v0.1.2
   Compiling rand v0.6.5
   Compiling rand_os v0.1.3
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 2.76s
peter@hp-laptop:~/rust-practice/chapter02/guessing_game$

cargo build가 처음 실행되었을 때 이 연관된 패키지들의 버전이 Cargo.lock에 기록되는데
우리는 Cargo.lock으로 인해 의존 패키지가 업데이트되었을 때
업데이트 버전이 우리 프로젝트와 호환되지 않더라도 기존 버전을 유지하며 사용할 수 있다.
Cargo.toml에 지정된 조건에 맞는 가장 최신 버전을 사용하고 싶다면
다음 명령어를 통해 업데이트하여 Cargo.lock을 갱신할 수 있다.

~/rust-practice/chapter02/guessing_game$ cargo update

Cargo에 대한 더 자세한 이야기는 나중으로 미루고 난수 생성으로 돌아오자.

~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
        .expect("Fail to read line");
   
    println!("You guessed: {}", guess);
}

난수 생성을 위해 use rand::Rng;가 추가되었다.
이것은 난수 생성기에 구현된 메서드를 정의하는 트레이트trait인데
이 녀석을 가져와야 해당 메서드를 사용할 수 있다는 것만 알고 넘어가자.
트레이트에 대한 건 추후에 제대로 다룰 예정이다.

let secret_number = rand::thread_rng().gen_range(1, 101);에서 난수를 생성한다.
rand::thread_rng()은 난수 생성기를 반환하며
난수 생성기의 메서드 gen_range에 전달한 인자 범위의 정수값이 secret_number에 bind된다.
범위는 첫번째 인자 이상 두번째 인자 미만으로 정해진다.
앞에서 use rand::Rng;을 해주지 않으면 이 gen_range를 사용할 수 없게 된다.
난수를 생성할 땐 시드 값이 필요한데 Rust의 난수 생성기는 운영체제로부터 시드 값을 받는다.

그리고 나중에 삭제하겠지만 난수가 잘 생성되었는지 확인하기 위한
println!("The secret number is: {}", secret_number);가 작성되었다.

이제 실행해보면 난수가 생성되는 것을 확인할 수 있다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.24s
     Running `target/debug/guessing_game`
Guess the number!
The secret number is: 72
Please input your guess.
78
You guessed: 78

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

그리고 당연하게도 다시 실행해보면 다른 값이 생성된다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/guessing_game`
Guess the number!
The secret number is: 82
Please input your guess.
28
You guessed: 28

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$

비교하기

이제 플레이어의 예측값과 생성된 난수값을 비교하여
비교 결과를 알려준다.
에 해당하는 부분을 작성해보자.

비교할 때 유의해야 할 점은, 표준 입력은 문자열의 형태로 읽어온다는 것이다.
즉, 난수 정수값과 직접 비교하려고 하면 자료형이 다르기 때문에 불가능하다.
// 물론 이게 가능한 언어도 존재하지만, Rust는 자료형에 민감하다, 매우!

그런 의미에서 먼저 값을 비교하기 전에 예측값을 정수로 변환하자.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
        .expect("Fail to read line");
  
    let guess: u32 = guess.trim().parse()
        .expect("Please type a number!");
  
    println!("You guessed: {}", guess);
}

우리는 u32 자료형의 guess 변수를 만들었다.
u32는 Rust의 정수 자료형 중 하나로, 부호가 없는 32bit 정수를 의미한다.
변수 선언은 let <변수 이름>: <자료형>;으로 이루어지며,
컴파일 시점에 자료형이 명확한 경우에만 자료형을 생략할 수 있다.
앞서 선언한 다른 변수들은 그것이 명확해서 생략된 것이다.

그런데 guess라는 이름의 변수는 기존에 선언된 바가 있다.
하지만 Rust는 shadowing이라는 기능으로 기존의 값을 가리고 같은 이름의 변수를 선언할 수 있다.
shadowing을 사용하면 기존의 값은 그 변수의 이름으로 접근할 수 없다.
이 기능은 guess_str과 같이 개별 변수를 따로 만들지 않고
변환한 변수를 같은 이름으로 저장할 수 있다는 편의성을 제공한다.
우리는 기존의 guess가 가진 문자열에서 trim 메서드를 통해 개행문자와 같은 공백을 제거하고
parse 메서드를 통해 구문분석을 하여 숫자를 반환한다.
숫자로 변환할 수 없는 문자열이었을 경우 expect가 프로그램을 종료하고
숫자로 변환되면 그 값을 새로 선언한 guess에 bind한다.

자, 이제 예측값과 난수값을 비교할 수 있게 되었으니 이에 해당하는 코드를 작성해보자.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
        .expect("Fail to read line");
  
    let guess: u32 = guess.trim().parse()
        .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!"),
    }
}

이번에는 use std::cmp::Ordering;이 추가되었다.
OrderingResult와 마찬가지로 열거형이다.
이것은 Less, Greater, Equal 세 개의 값을 가지고 있다.
cmp 메서드는 비교가 가능한 어떤 값에도 사용할 수 있는데
그 값과 인자로 전달된 값을 비교하여 그 결과를 Ordering 열거값으로 반환한다.
그 값이 인자로 전달된 값에 비해 어떠한가를 반환하는 것이다.

cmp 매서드의 반환값이 각각의 열거값에 해당할 때의 코드는
match라는 비교 구문을 사용하여 작성할 수 있다.
match 표현식에 대해서는 이후에 다시 이야기하겠지만
<패턴> => <실행문> 형태의 arm으로 구성되어 있으며
match와 중괄호 사이의 값이 어떤 패턴과 일치하면 그 arm의 실행문이 실행되는 형태다.
우리는 guess.cmp(&secret_number)의 반환값을 그 기준값으로 사용한다.

실행해보면 값의 대소관계에 따라 문자열이 출력되는 것을 확인할 수 있다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.35s
     Running `target/debug/guessing_game`
Guess the number!
The secret number is: 44
Please input your guess.
28
You guessed: 28
Too small!
peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

그런데 이렇게 한 번 시도하고 끝나면 제대로 된 숫자 맞히기 게임이 되지 않는다.
따라서 반복문을 통해 계속 입력 받고, 정답을 맞췄을 때 종료할 필요가 있다.

반복하기

유의미한 게임이 되도록 하기 위해서 반복문을 사용하여
플레이어의 예측값이 생성된 난수값과 일치하면
축하 메시지를 출력 후 종료한다.
에 해당하는 부분을 작성하자.

반복을 사용하는 방법은 다양하지만 무한 반복을 하는데 사용되는 loop를 사용해보겠다.
이것은 말 그대로 무한 반복이므로 반복 조건에 따라 반복을 종료하는 코드를 포함시키는 게 중요하다.
물론 종료 조건이 없어도 ctrl + c를 통해 강제 종료할 수는 있긴 하다.
하지만 적절한 종료 조건을 통해 로직 상의 종료를 구현하는 것이 좋다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
            .expect("Fail to read line");
      
        let guess: u32 = guess.trim().parse()
            .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;
            },
        }
    }
}

loop를 사용하여 무한 반복을 하게 수정하였으며
match 구문의 Ordring::Equal에 해당하는 arm의 실행문을 코드블록으로 바꾸어
반복에서 벗어나기 위한 break;를 추가하였다.

이제 실행해보면 반복적으로 수행되는 것을 알 수 있다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/guessing_game`
Guess the number!
The secret number is: 42
Please input your guess.
28
You guessed: 28
Too small!
Please input your guess.
78
You guessed: 78
Too big!
Please input your guess.
42
You guessed: 42
You win!
peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

기능 상의 보완

지금 우리 프로그램은 사용자가 숫자가 아닌 값을 입력하면 그대로 종료된다.
하지만 그것보다는 사용자로 하여금 다시 입력하도록 하는 것이 좋을 것이다.
우리는 열거형과 match를 이용하여 비교문을 작성하는 것을 해봤으니
Result의 열거값을 통해 이를 처리하는 것도 금방 할 수 있을 것이다.

그리고 하는 김에 더이상 필요하지 않은, 난수값 출력 코드도 제거하겠다.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ vi src/main.rs

src/main.rs

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)
            .expect("Fail 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;
            },
        }
    }
}

이제 guess.trim().parse()가 성공했을 경우에만 그 결과가 guess에 bind되고
그렇지 않을 경우 continue를 만나 반복문의 시작 부분으로 돌아간다.

이제 다시 실행해보자.

peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ cargo run
   Compiling guessing_game v0.1.0 (/home/peter/rust-practice/chapter02/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
78
You guessed: 78
Too small!
Please input your guess.
guess
Please input your guess.
it is not a number!
Please input your guess.
93
You guessed: 93
You win!
peter@hp-laptop:~/rust-practice/chapter02/guessing_game$ 

실시간 피터 "왜 맞았지? 그냥 적당히 큰 값이었는ㄷ..."

자, 이걸로 우리는 작동하는 하나의 Rust 프로그램, 숫자 맞추기 게임을 구현했다.
무언가 구현해냈다는 뿌듯함과 함께 그래서 이게 어떻게 작동되는가 하는 궁금증이 생긴다.
그 궁금증을 가지고 호기심을 유지한 채! 다음 내용으로 넘어가보자.

이 포스트의 내용은 공식문서의 2장 Programming a Guessing Game에 해당합니다.

profile
Peter J Online Space - since July 2020

2개의 댓글

comment-user-thumbnail
2021년 7월 12일

잘 읽었습니다!👍👍👍
짤막한 업데이트 글귀..!
현재 (2021.07.12) rand crate의 최신 버전은 0.8.4이고,
get_range 메소드는 아래처럼 인자를 하나만 받게 되었습니다.

let secret_number = rand::thread_rng().gen_range(1..101);
1개의 답글