TRPL - Programming a Gussing Game

EN·2023년 12월 11일
0

Rust

목록 보기
2/2
post-thumbnail

Processing a Guess

use std::io;

  • 스탠다드 라이브러리의 io(인풋, 아웃풋)
  • 이걸 러스트에선 prelude라고 한다.

Storing Values with Variables

let과 let mut

  • let apples = 5; //immutable
  • let mut bananas = 5; // mutable

String::new

  • String의 새로운 인스턴스를 리턴하는 함수
  • :: 라는 것은 new라는게 String에 연관된 함수라는 것임.

Receiving User Input

io::stdin().read_line(&mut guess)

  • 여기서 guess는 입력을 저장할 변수 이름.
  • &은 C++과 마찬가지로 reference를 의미함.

Handling Potential Failure with Result

.expect("Failed to read line");

io::stdin().read_line(&mut guess).expect("Failed to read line");
  • read_line 함수는 Result value를 리턴함.(Result = enumaration, 열거형)
  • Result는 Ok 또는 Err로 이루어져있음.
  • expect로 Result를 처리해주지 않으면 경고를 받음.

Generating a Secret Number

이제 1부터 100까지 수를 랜덤하게 만드는 예시를 해 볼것임.

Using a Crate to Get More Functionality

Cargo의 외부 crates와의 조화는 Cargo의 매력이다!!
이제 외부 라이브러리 추가해볼 것.

cargo.toml파일 하위에 [dependencies]에 rand = "0.8.5"추가.
이때 일어나는 일?

  • Cargo는 Semantic Versioning(Semver라고도 부름)을 파악한다.
  • 여기서 0.8.5라는 것은 적어도 0.8.5이지만 0.9.0 미만이라는 것을 의미함.
  • Crates.io 라는 곳이 있음. 여기서 데이터 사본(registry)을 가져와서 필요한걸 가져온다는 것 같음. (When we include an external dependency, Cargo fetches the latest versions of everything that dependency needs from the registry, which is a copy of data from Crates.io. Crates.io is where people in the Rust ecosystem post their open source Rust projects for others to use.)
  • registry를 업데이트 하고 나서, dependencies 섹션에서 필요한 모든 crates를 다운로드 한다는듯.

Ensuring Reproducible Builds with the Cargo.lock File

Cargo.lock파일에 대해서 좀 더 설명하는 부분이다.
요약하자면, Cargo는 Cargo.lock파일을 보면서 "어떤 버전들을 사용할 것인지"를 파악한다.
이걸 Reproducible builds라고 하네
그럼, dependencies의 버전들을 좀 업데이트하고싶을 땐??
아래에서 나오는 updatea명령어를 통해서 할 수 있는 것임.

Updating a Crate to Get a New Version

cargo update라는 명령어를 수행했다고 해보자.
만약 0.8.6버전이 나오고, 그 뒤에 0.9.0이 출시되었다고 하자.(현재는 0.8.5라고 가정)
cargo update를 하면 0.8.6이 될까? 0.9.0이 될까?
이건 0.8.6이 된다.
Cargo.toml 파일에서 0.9.0이라고 명시해주지 않으면 below 0.9.0을 유지한 update가 수행된다고 한다.

Generating a Random Number

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

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

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

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

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

    let mut guess = String::new();

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

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

use rand::Rng;

  • Rng에서 랜덤 숫자 생성에 대한 구현이 있는것임.

Comparing the Guess to the Secret Number

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

fn main() {
    // --snip--

    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

  • Ordering이라는 열거형을 사용하겄다(Greater, Equal, Less라는게 값으로 있음)

match

  • 이 expression은 arms로 이루어져 있음.
  • 하나의 arm은 pattern으로 구성되어있음.

프로그램을 실제로 돌려보면 에러가 뜰텐데, 자료형을 어떻게 해야할까? 라는 생각이 들었음.

    // --snip--

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("Failed 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!"),
    }

여기서 guess를 또 사용한 것을 볼 수 있는데,
이런걸 Shadowing이라고 한다.
새로운 guess를 만드는게 아닌, 기존의 guess 변수를 재사용한다는것.

Allowing Multiple Guesses with Looping

    // --snip--

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

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

        // --snip--

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

이런식으로 loop를 사용한다.
종료조건은 어떻게 표기할까?

Quitting After a Correct Guess

        // --snip--

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

약간 Swift에서 클로저가 생각이 난다.

그리고 잘못된 입력은 어떻게 처리할까?

Handling Invalid Input

        // --snip--

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

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

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

        // --snip--

이것도 마찬가지로 parse()에서 Result를 리턴하는 듯 하다.

뭔가... C++과 비슷하면서도...
또 완전 새로운 세상인 것 같다.
C++과 Swift의 문법이 섞인듯한 느낌...

profile
iOS/JUJITSU

0개의 댓글