간단하게 정리해본 Rust 강좌입니다.
다음 문서를 기반으로 작성했습니다.
Tour of Rust https://tourofrust.com/00_ko.html
.
2022. 09. 07 최초작성
2023. 03. 23
2026. 03. 23 최종작성
.
Rust 개발 환경 만드는 방법은 아래 포스트를 참고하세요.
.
if/else
if/else 문을 사용하면 if 문에 주어지는 조건에 따라 원하는 코드를 실행하도록 할 수 있습니다.
if문에 조건을 지정할때 다음과 같은 관계 연산자와 논리 연산자를 사용할 수 있습니다.
.
관계 연산자
- == : 양변에 있는 값이 갔다는 의미입니다.
- != : 양변에 있는 값이 같지 않다는 의미입니다.
- < : 오른쪽 값이 더 크다는 의미입니다.
- > : 왼쪽 값이 더 크다는 의미입니다.
- <= : 오른쪽 값이 더 크거나 양변의 값이 같다는 의미입니다.
- >= : 왼쪽 값이 더 크거나 양변의 값이 같다는 의미입니다.
.
논리 연산자
- ! : 뒤에 주어지는 조건이 True가 아닌 경우에 조건이 True가 됩니다.
- || : 좌우에 있는 조건 중 하나만 만족해도 조건이 True가 됩니다. 왼쪽 조건의 우선순위가 더 높습니다.
- && : 좌우에 있는 조건이 모두 만족해야 조건이 True가 됩니다.
.
다음 코드는 변수 x에 저장된 값이 42보다 작은지, 42와 같은지, 아니면 42보다 큰지에 따라 다른 출력을 하는 예제입니다.
| fn main() { // 변수 x에 42를 저장합니다. let x = 42; // 변수 x의 값이 42보다 작다면 조건 x < 42가 true가 되어 바로 아래 블럭 안에 있는 코드가 실행됩니다. // 변수 x의 값이 42보다 크거나 같으면 조건 x < 42가 false가 되어 else문으로 넘어갑니다. if x < 42 { println!(“42보다 작다”); } else if x == 42 { // 변수 x의 값이 42와 같다면 조건 x == 42가 true가 되어 바로 아래 블럭 안에 있는 코드가 실행됩니다. // 변수 x의 값이 42가 아니라면 조건 x == 42가 false가 되어 else문으로 넘어갑니다. println!(“42와 같다”); } else { // if 문이 없고 else만 있는 경우 아래 있는 블럭의 코드가 바로 실행됩니다. // 이 경우는 앞에서 체크한 조건에 모두 해당하지 않은 경우입니다. println!(“42보다 크다”); } } |
.
변수 x에는 42가 저장되어 있기 때문에 실행해보면 “42와 같다”가 출력됩니다.
.
실행 결과
42와 같다
.
.
다음 코드처럼 if 문에서 값을 전달받아서 변수 v에 저장할 수 있습니다. if /else문 다음에 나오는 블럭의 마지막줄에 적은 값이나 변수의 값이 리턴됩니다. 아래 코드에선 조건 x == 42를 만족했는지 여부에 따라 “42임” 또는 “42아님”이 변수 v에 저장됩니다.
| fn main() { let x = 42; let v = if x == 42 { “42임” } else { “42아님” }; println!(“{}”, v); } |
.
변수 x에는 42가 저장되어 있기 때문에 if문에서 “42임”을 전달받아 변수 v에 저장됩니다.
.
실행 결과
42임
.
.
loop
loop 문을 사용하면 블록 내에 있는 코드를 무한 반복을 합니다.
if 문으로 조건을 체크하여 만족하면 break를 사용하여 무한 반복을 중단할 수 있습니다.
| fn main() { //변수의 값을 변경해야 하므로 let대신에 let mut를 사용하여 변수를 선언해야 합니다. let mut x = 0; // 무한 루프입니다. 블럭 {} 안의 코드를 반복합니다. loop { // 변수 x에 1을 더합니다. x += 1; // 변수 x가 42가 되면 break를 사용하여 무한 루프에서 빠져나옵니다. if x == 42 { break; } } println!(“{}”, x); } |
.
실행결과 42가 출력됩니다.
42
.
.
loop에서 break을 사용하여 반복을 중단하면서 값을 리턴받아 변수에 저장할 수 있습니다.
다음 코드는 5개의 문자가 저장된 배열에서 원하는 문자가 있는 위치를 출력합니다.
| fn main() { // 변수 array에 5개의 문자로 구성된 배열을 대입합니다. let array: [char; 5] = [‘A’, ‘A’, ‘A’, ‘C’, ‘A’]; // index를 1씩 증가시키면서 루프에서 현재 인덱스가 가리키는 배열 array의 원소가 ‘C’인지 검사합니다. let mut index = 0; let ret = loop { // 현재 index가 가리키는 배열 원소의 값이 ‘C’인지 검사합니다. if array[index] == ‘C’ { // break 문에 의해서 반복을 중단하면서 index에 저장된 값을 변수 ret에 전달합니다. break index; } index += 1; }; // 배열 array의 4번째 문자가 ‘C’이므로 3이 출력됩니다. println!(“loop의 리턴값 : {}”, ret); } |
.
.
5개의 문자열이 저장되어있는 배열로 바꾸어 봅니다.
| fn main() { // 변수 array에 5개의 문자열로 구성된 배열을 대입합니다. let array: [&str; 5] = [“Apple”, “Apple”, “Apple”, “Cat”, “Apple”]; // index를 1씩 증가시키면서 루프에서 현재 인덱스가 가리키는 배열 array의 원소가 “Cat”인지 검사합니다. let mut index = 0; let ret = loop { // 현재 index가 가리키는 배열 원소의 값이 “Cat”인지 검사합니다. if array[index] == “Cat” { // break 문에 의해서 반복을 중단하면서 index에 저장된 값을 변수 ret에 전달합니다. break index; } index += 1; }; // 배열 array의 4번째 문자열이 ‘Cat’이므로 3이 출력됩니다. println!(“loop의 리턴값 : {}”, ret); } |
.
앞에서 사용한 코드가 위험한 코드가 될 수 있습니다. 배열에서 조건을 만족하는 것을 찾지 못하면 다음과 같은 에러가 발생합니다. 테스트 삼아 위 코드의 14번째 줄에 있는 if 문의 Cat을 Dog로 변경해보세요.
thread ‘main’ panicked at ‘index out of bounds: the len is 5 but the index is 5’, src/main.rs:14:12
.
.
while
while 문도 블럭 {} 안의 코드를 반복을 합니다. loop 문과 차이는 while 키워드 뒤에 오는 조건을 만족하는 동안에만(조건이 true인 동안에만) 블록 내에 있는 코드를 반복합니다.
| fn main() { // 값을 변경해야 하므로 let mut를 사용하여 변수를 선언해야 합니다. let mut x = 0; // 변수 x의 값이 10이 아닌 동안 반복합니다. while x != 10 { // 변수 x의 값을 1 증가시킵니다. x += 1; } // 실행결과 10이 출력됩니다. println!(“{}”, x) } |
.
.
for
for 문을 사용하면 지정한 범위내에서 반복할 수 있습니다.
in 다음에 .. 연산자를 사용하면 시작값으로 주어진 정수부터 끝값으로 주어진 정수 전까지 반복하게 됩니다.
in 다음에 ..= 연산자를 사용하면 시작값으로 주어진 정수부터 끝값으로 주어진 정수까지 반복하게 됩니다.
| fn main() { // 끝값 5를 제외하고 0 ~ 4까지 정수를 출력합니다. for x in 0..5 { println!(“{}”, x); } println!(“”); // 끝값 5를 포함하여 0 ~ 5까지 정수를 출력합니다. for x in 0..=5 { println!(“{}”, x); } } |
.
실행결과
0
1
2
3
4
0
1
2
3
4
5
.
.
match
C/C++의 switch 문과 유사합니다.
match 키워드 다음에 주어진 변수 x의 값에 대해 조건들을 검사하여 일치하면 해당 코드를 실행합니다.
| fn main() { let x = 1; match x { // 변수 x의 값이 1인 경우입니다. 1 => println!(“1입니다.”), // 변수 x의 값이 2인 경우입니다. 2 => println!(“2입니다.”), // 나머지 경우가 해당됩니다. _=>println!(“다른 숫자군요.”), } } |
실행결과 “1입니다”가 출력됩니다.
.
.
다음처럼 match를 문자열에 대해서도 사용할 수 있습니다.
| fn main() { let x = String::from(“abc”); match x.as_str() { // 변수 x의 값이 ABC인 경우입니다. “ABC” => println!(“대문자 ABC입니다.”), // 변수 x의 값이 abc인 경우입니다. “abc” => println!(“소문자 abc입니다.”), // 나머지 경우가 해당됩니다. _=>println!(“다른 문자열 이군요.”), } } |
실행결과
소문자 abc입니다.
.
.
다양한 방식으로 match 문에 조건을 추가할 수 있습니다.
| fn main() { let x = 42; match x { // 하나의 값과 일치하는 경우입니다. 0 => { println!(“0과 일치”); } // 두개의 값중 하나와 일치하는 경우입니다. 1 | 2 => { println!(“1 또는 2와 일치!”); } // 범위 내의 숫자와 일치하는 경우입니다. 3..=9 => { println!(“3에서 9사이의 숫자와 일치”); } // 찾은 숫자를 변수에 대입할 수 있습니다. matched_num @ 10..=100 => { println!(“10에서 100사이의 숫자 {}와 일치!”, matched_num); } // 앞에서 지정한 조건에 매칭이 안된경우 실행되는 코드입니다. _ => { println!(“일치하는 조건이 없었음”); } } } |
실행결과
10에서 100사이의 숫자 42와 일치 !
.
.
다음처럼 match 문에서 값을 전달받아 변수 result에 저장할 수 있습니다.
| fn main() { let food = “햄버거”; let result = match food { // 변수 food의 값이 핫도그인 경우입니다. “핫도그” => “핫도그다”, // 전달되는 값이 하나라면 중괄호 {}는 필수가 아닙니다. _ => “핫도그가 아니다”, }; // 실행결과 핫도그가 아니다가 출력됩니다. println!(“{}”, result); } |
.
.
블록에서 값 리턴하기
블록 끝에 값이나 변수가 주어지면 블록 밖에 있는 변수에 대입됩니다.
| fn main() { // 블럭 마지막에 있는 a + b의 결과값이 리턴되어 변수 v에 저장됩니다. let v = { let a = 1; let b = 2; a + b }; // 실행결과 3이 출력됩니다. println!(“{}”, v); } |
.
.
구조체(struct)
구조체는 struct 키워드로 선언됩니다.
| // println! 함수를 사용하여 구조체를 출력해보려면 디버깅 모드를 사용해야 합니다. #[derive(Debug)] // 두개의 변수로 구성된 구조체 Vec2를 선언합니다. struct Vec2 { _x: f64, _y: f64, } fn main() { // 2개의 구조체를 선언합니다. // 순서는 중요하지 않으며 변수이름만 중요합니다. let v1 = Vec2 { _x: 1.0, _y: 3.0 }; let v2 = Vec2 { _y: 2.0, _x: 4.0 }; // 디버깅 모드를 사용하여 구조체 출력시 다음 두가지 차이를 아래 결과에서 비교해보세요. println!(“{:#?}”, v1); println!(“{:?}”, v2); } |
.
실행결과

.
.
다른 구조체의 값을 가져와 구조체의 값을 채울 수 있습니다.
아래 예제에서는 구조체 v2의 값을 사용하여 구조체 v3의 일부 필드와 구조체 v4의 전체 필드를 채우고 있습니다.
| #[derive(Debug)] struct Vec2 { _x: f64, _y: f64, } fn main() { // 2개의 구조체를 선언합니다. // 순서는 중요하지 않으며 필드 이름만 중요합니다. let v1 = Vec2 { _x: 1.0, _y: 3.0 }; let v2 = Vec2 { _y: 2.0, _x: 4.0 }; // 구조체 v3의 _y값이 구조체 v2의 _y값으로 채워집니다. let v3 = Vec2 { _x: 14.0, ..v2 }; // 구조체 v4의 _x,_y의 값이 구조체 v2의 값으로 채워집니다. let v4 = Vec2 { ..v2 }; println!(“{:#?}”, v1); println!(“{:?}”, v2); println!(“{:#?}”, v3); println!(“{:#?}”, v4); } |
.
실행결과

.
.
구조체도 튜플처럼 값을 나누어 저장할 수 있습니다.
| struct Vec2 { _x: f64, _y: f64, } fn main() { // 2개의 필드를 가지는 구조체를 선언합니다. let v = Vec2 { _x: 3.0, _y: 6.0 }; // 구조체 v에 저장된 값이 변수 _x와 _y에 나누어 저장됩니다. let Vec2 { _x, _y } = v; println!(“{} {}”, _x, _y); // 필드 _y의 값은 버려집니다. let Vec2 { _x, .. } = v; println!(“{}”, _x); } |
.
실행결과
3 6
3
.
.
let 구조체 구문을 if문의 조건으로 사용할 수 있습니다.
| struct Number { odd: bool, value: i32, } fn print_number(n: Number) { // value 필드의 값이 0이라면, odd 필드는 조건으로 사용하지 않지만 적어줘야 합니다. if let Number { odd, value:0 } = n { println!(“Number is Zero: {}”, n.value); } // odd 필드의 값이 true라면, value 필드는 조건으로 사용하지 않지만 적어줘야 합니다. else if let Number { odd: true, value } = n { println!(“Odd number: {}”, value); } // odd 필드의 값이 false라면, value 필드는 조건으로 사용하지 않지만 적어줘야 합니다. else if let Number { odd: false, value } = n { println!(“Even number: {}”, value); } } fn main() { let one = Number { odd: true, value: 1 }; let two = Number { odd: false, value: 2 }; let zero = Number { odd: false, value: 0 }; print_number(one); print_number(two); print_number(zero); } |
.
실행결과
Odd number: 1
Even number: 2
Number is Zero: 0
.
.
구조체를 match문의 패턴으로 사용할 수 있습니다.
| struct Number { odd: bool, value: i32, } fn print_number(n: Number) { // 구조체 n을 검사합니다. match n { // value 필드 값이 0이고 odd 필드 값이 false라면, 필드 순서가 구조체 정의와 다르게 바뀌어도 상관없습니다. Number { value:0, odd: false} => println!(“Number is Zero: {}”, n.value), // odd 필드 값이 true라면, ..을 사용하여 value 필드를 생략할 수 있습니다. Number { odd: true, .. } => println!(“Odd number”), // odd 필드 값이 false라면, value 필드는 조건으로 사용하지 않지만 적어줘야 합니다. Number { odd: false, value } => println!(“Even number: {}”, value), } } fn main() { let one = Number { odd: true, value: 1 }; let two = Number { odd: false, value: 2 }; let zero = Number { odd: false, value: 0 }; print_number(one); print_number(two); print_number(zero); } |
.
실행결과
Odd number
Even number: 2
Number is Zero: 0
.
.
match 문을 사용하여 구조체의 일부 필드의 값을 검사할 수 있습니다.
| struct Number { odd: bool, value: i32, } fn print_number(n: Number) { match n { // value 필드 값이 1이라면 Number { value: 1, .. } => println!(“One”), // value 필드 값이 2라면 Number { value: 2, .. } => println!(“Two”), Number { value, .. } => println!(“{}”, value), // 이 줄이 없으면 컴파일시 에러납니다. } } fn main() { let one = Number { odd: true, value: 1 }; let two = Number { odd: false, value: 2 }; print_number(one); print_number(two); } |
.
실행결과
One
Two
.
.
match에서 언더바(_)를 사용하여 앞에서 지정하지 않은 나머지 조건에 대해 처리하도록 할 수 있습니다.
| struct Number { odd: bool, value: i32, } fn print_number(n: Number) { // 구조체의 value 필드의 값을 검사합니다. match n.value { // 1인 경우 1 => println!(“One”), // 2인 경우 2 => println!(“Two”), // n.value값이 1과 2가 아닌 경우에 대한 처리를 하게 됩니다. _ => println!(“{}”, n.value), } } fn main() { // 구조체 3개를 선언합니다. let one = Number { odd: true, value: 1 }; let two = Number { odd: false, value: 2 }; let three = Number { odd: false, value: 3 }; print_number(one); print_number(two); print_number(three); } |
.
실행 결과
One
Two
3
.
.
메소드 호출하기
함수와 달리, 메소드는 특정 데이터 타입과 연관된 함수입니다.
- 정적 메소드(static methods) – 데이터 타입 그 자체에 속하는 메소드로서, :: 연산자를 이용하여 호출함.
- 인스턴스 메소드(instance methods) – 데이터 타입의 인스턴스에 속하는 메소드로서, . 연산자를 이용하여 호출함.
| fn main() { // 정적 메소드를 사용하여 String의 인스턴스를 생성 let s = String::from(“Hello world!”); // 인스턴스의 메소드를 사용 println!(“{}의 글자 수는 {}입니다.”, s, s.len()); } |
.
.