두 정수 A와 B를 입력받은 다음, A-B를 출력하는 프로그램을 작성하시오.
첫째 줄에 A와 B가 주어진다.(0<A, B<10)
첫째 줄에 A-B를 출력한다.
3 2
1
use std::io;
fn main() {
println!("Please enter numbers: ");
let mut number = String::new();
io::stdin().read_line(&mut number).unwrap();
let numbers: Vec<&str> = number.split_whitespace().collect();
let number_first = numbers[0].parse::<i32>().unwrap();
let number_second = numbers[1].parse::<i32>().unwrap();
println!("{}", number_first - number_second);
}
use std::io;
std::io
모듈을 가져옵니다. 이 모듈은 표준 입출력을 포함한 여러 I/O 관련 기능을 제공합니다.
fn main() {
: Rust 프로그램의 메인 함수를 정의합니다. 모든 Rust 프로그램은 main 함수에서 시작
됩니다.
let mut input = String::new();
input이라는 이름의 가변(mut) String 변수를 생성하고 초기화합니다. 이 변수에 사용자의 입력을 저장할 것입니다.
let mut input = String::with_capacity(50);
미리 정해진 용량으로 빈 문자열을 생성할 수 있습니다.std::io::Read
트레이트의 read_to_string()
메서드를 사용할 수도 있습니다:use std::io::{self, Read};
io::stdin().read_line(&mut input).expect("Failed to read line")
:
4.1. io::stdin() 메서드는 Rust의 표준 라이브러리인 std::io 모듈에서 제공하는 함수입니다. 이 메서드는 표준 입력 (stdin)을 나타내는 std::io::Stdin 타입의 인스턴스를 반환합니다. Stdin 인스턴스는 사용자로부터의 입력을 읽어들이는 데 사용됩니다.
4.2. read_line() :
- std::io::Stdin 타입의 인스턴스에서 제공되는 함수
- 사용자로부터의 입력을 읽어들여 문자열에 저장
- Result 타입을 반환
- 입력 읽기 중 발생할 수 있는 오류를 처리
4.3. unwrap() : Result 타입 또는 Option 타입의 값에 대해 호출할 수 있는 메서드.
- Result : Result::Ok variant인 경우 내부의 값을 반환하고, Result::Err variant인 경우 패닉(panic)을 발생시켜 프로그램을 중단합니다.
- Option : Option 타입의 경우, Option::Some variant인 경우 내부의 값을 반환하고, Option::None인 경우 패닉(panic)을 발생시켜 프로그램을 중단합니다.
- 주로 디버깅이나 프로토타이핑에 사용되며, 실제 프로덕션 코드에서는 대신 match 문이나 if let 구문을 사용하여 에러 처리를 명시적으로 하는 것이 권장됩니다.
let nums: Vec<i32> = input: nums
라는 이름의 Vec<i32>
타입 변수를 선언하고, 아래의 메서드 체인을 사용하여 값을 할당합니다.
5.1. rust에서 Vec과 같은 타입을 컬렉션
이라함
컬렉션
: 여러 데이터를 저장하는 구조이며 동적으로 변함
컬렉션 데이터 타입 종류
1.Vec<T>
:동적 크기의 배열
로, 연속된 메모리에 저장되어 있으며인덱스
를 사용하여 빠른 접근이 가능합니다.요소를 추가
하거나제거
할 때 크기가 동적으로 변경됩니다. 요소가 삽입되거나 제거될 때 다른 요소를 이동해야 하므로 뒷부분의 추가 및 제거 작업은 느릴 수 있습니다.
2.LinkedList<T>
: 연결 리스트로, 각 요소가 다음 요소에 대한 포인터를 가집니다. 이를 통해 요소의 추가 및 제거가 빠르지만 인덱스를 사용한 랜덤 액세스가 불가능하므로 선형 탐색이 필요하며 상대적으로 느립니다.
3.HashMap<K, V>
: 해시 테이블 기반의 키-값 쌍을 저장하는 무순서 집합입니다. 빠른 검색, 삽입 및 제거 작업이 가능하지만, 키에 대한 순서를 유지하지 않습니다.
4.BTreeMap<K, V>
: 이진 탐색 트리 기반의 키-값 쌍을 저장하는 정렬된 맵입니다. 키 순서를 유지하며 상대적으로 빠른 검색, 삽입 및 제거 작업이 가능합니다.
5.HashSet<T>
: 유일한 요소를 저장하는 무순서 집합입니다. 요소의 검색, 삽입 및 제거 작업이 빠르지만, 순서를 유지하지 않습니다.
6.BTreeSet<T>
: 유일한 요소를 저장하는 정렬된 집합입니다. 요소 순서를 유지하며 상대적으로 빠른 검색, 삽입 및 제거 작업이 가능합니다.
Vec는 Rust에서 가장 기본적이고 자주 사용되는 컬렉션 타입 중 하나이므로, std::collections 모듈을 명시적으로 가져오지 않아도 사용할 수 있습니다. Vec는 표준 라이브러리의
prelude 부분에 포함되어 있어 자동으로 스코프에 포함되기 때문
입니다.
다른 컬렉션 타입들을 사용하려면 std::collections 모듈을 명시적으로 가져와야 합니다. 예를 들어,HashMap
이나HashSet
을 사용하려면 다음과 같이작성해야 합니다
use std::collections::HashMap;
use std::collections::HashSet;
Rust에서 타입을 명시하지 않고도 변수에 값을 할당 할 수 있습니다.
컴파일러가 타입을 추론 할 수 있기 때문
예: 변수를 초기화 할 때 컴파일러는 초기 값의 타입을 기반으로 변수의 타입을 추론합니다.
let numbers = vec![1, 2, 3]; // 타입 추론에 의해 Vec<i32>
let names = vec![String::from("Alice"), String::from("Bob"), String::from("Carol")]; // 타입 추론에 의해 Vec<String>
모든 경우에 타입 추론이 가능하지 않음.
- 제네릭 함수에서 타입을 지정하지 않고 사용하려면 컴파일러가 타입을 추론할 수 있는 정보
가 필요함.
데이터 컬렉션의 타입을 명시하지 않고 사용하는 것은 불가능.
컴파일러는 대부분의 경우 타입 추론을 사용하여 타입을 결정 할 수 있지만, 컬렉션의 경우에는 구체적인 타입을 제공해야함.
5.2. split_whitespace()
반환 타입: std::str::SplitWhitespace
반복자(iterator)
str 타입의 문자열에 적용되는 메서드
String 타입의 문자열에도 쉽게 사용
String 타입의 문자열
은 str 타입의 문자열로 자동으로 참조될 수 있기 때문
str 타입의 문자열로 자동으로 참조될 수 있기 때문
String 타입과 str 타입은 서로 다른 문자열 타입입니다.
String 타입은 동적으로 할당되고 변경 가능한 문자열이고, str 타입은 불변이고 고정된 크기를 가진 문자열입니다. String 타입의 문자열은 str 타입의 문자열로 자동으로 참조될 수 있다는 말은,String 타입의 문자열이 str 타입을 참조하는 슬라이스 형태로 자동 변환
될 수 있다는 뜻입니다. 이 변환은Rust에서 자동으로 처리
해주기 때문에 프로그래머는 크게 신경 쓰지 않아도 됩니다.
예시
let s: String = String::from("Hello, world!");
let r: &str = &s;
String 타입의 s 변수는 &str 타입의 r 변수에 대입됩니다. 이때 s가 자동으로 str 타입을 참조하는 슬라이스 형태로 변환되어 r에 대입됩니다. 이 변환 과정이 자동으로 이루어져서, 프로그래머는 따로 변환을 처리하지 않아도 됩니다. 이러한 특성 덕분에 split_whitespace와 같은 메서드를 String과 str 타입 모두에 사용할 수 있습니다.
5.3. collect()
: 제네릭 메서드
는 입력 타입과 반환 타입을 런타임에서 결정하기에 반환 타입 추론이 어려움.
B
이며 FromIterator<Self::Item>
트레잇을 구현하는 타입이어야 함.<>
), 타입 매개변수를 포함하고 있는지 아닌지를 통해 파악 할 수 있음. fn example_function<T>(input:T) -> T{
}
let result = example_function::<i32>(42);
let result = example_function(42); // 컴파일러가 i32 타입을 추론합니다.
참고2 : ::
기호는 무엇인가?
mod example{
pub fn hello(){
println!("hello, world!");
}
}
fn main() {
example::hello();// 모듈 example의 hello 함수를 호출합니다.
}
}
struct Example {
value: i32,
}
impl Example {
fn new(value: i32) -> Example{
Example { value }
}
}
fn main() {
let example = Example::new(42)
}
fn example_function<T>(input: T) -> T {
// 함수 구현
}
fn main() {
let result = example_function::<i32>(42);// 제네릭 함수에 명시적으로 i32 타입을 지정합니다.
}
trait ExampleTrait{
fn hello(&self);
}
struct Example;
impl ExampleTrait for Example {
fn hello(&self) {
println!("Hello, world!");
}
}
fn main() {
let example = Example;
ExampleTrait::hello(&example); //
}
6.let number_first = numbers[0].parse::<i32>().unwrap();
parse
FromStr
트레잇이 구현되어 있는지 확인하고, 구현되어 있다면 문자열을 해당 타입으로 변환
함use std::io;
fn main() {
println!("Please enter numbers: ");
let mut number = String::new();
io::stdin().read_line(&mut number).unwrap();
let numbers: Vec<&str> = number.split_whitespace().collect();
let number_first = match numbers[0].parse::<i32>() {
Ok(num) => num,
Err(_) => {
println!("Failed to parse the first number");
return;
}
};
let number_second = match numbers[1].parse::<i32>() {
Ok(num) => num,
Err(_) => {
println!("Failed to parse the second number");
return;
}
};
println!("{}", number_first - number_second);
}
use std::io;
fn main() {
println!("Please enter numbers: ");
let mut number = String::new();
io::stdin().read_line(&mut number).unwrap();
let numbers: Vec<&str> = number.split_whitespace().collect();
let number_first = if let Ok(num) = numbers[0].parse::<i32>() {
num
} else {
println!("Failed to parse the first number");
return;
};
let number_second = if let Ok(num) = numbers[1].parse::<i32>() {
num
} else {
println!("Failed to parse the second number");
return;
};
println!("{}", number_first - number_second);
}
// 출처 : gpt-4
use std::io;
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line");
let nums: Vec<i32> = input
.split_whitespace()
.map(|s| s.parse().expect("Failed to parse integer"))
.collect();
let a = nums[0];
let b = nums[1];
println!("{}", a - b);
}
map()
std::iter::Map
Iterator
트레잇에 정의된 메서드로 'Iterator`를 구현하는 모든 타입에서 사용 가능클로저
: 함수와 유사한 동작을 하는 익명의 코드 블록use std::io;
fn main() {
println!("Please enter numbers: ");
let mut number = String::new();
io::stdin().read_line(&mut number).unwrap();
let numbers: Vec<&str> = number.split_whitespace().collect();
let mut number_first: i32 = 0;
let mut number_second: i32 = 0;
for (index, num_str) in numbers.iter().enumerate() {
let num = num_str.parse::<i32>().unwrap();
if index == 0 {
number_first = num;
} else if index == 1 {
number_second = num;
break;
}
}
println!("{}", number_first - number_second);
}