Rust에는 소유권, 참조, 라이프타임 등 고유한 용어들이 있는데 이외에도 생소하거나 중요한 용어인 variant, field, pattern, match arm, block, scope, associated type, attribute에 대해서 살펴 보겠습니다.
1. variant
- 정의: enum에서 각각의 경우(상태/종류)를 의미.
- 예시:
enum Color {
Red,
Blue,
Green,
}
let c = Color::Red; // Red는 Color 타입의 variant
여기서 Red, Blue, Green이 각각 variant이다.
2. field
- 정의: struct(또는 enum의 variant)에 속하는 개별 데이터 항목.
- 예시:
struct Point {
x: i32, // field
y: i32, // field
}
let p = Point { x: 1, y: 2 };
x와 y가 각각 field이고, i32는 각각의 field의 타입(type of the field 또는 필드형/필드 타입)입니다.
enum Message {
Quit, // 필드 없음
Move { x: i32, y: i32 }, // 필드 x, y가 있는 구조체 스타일
Write(String), // 이름 없는 튜플 스타일의 필드 String
ChangeColor(i32, i32, i32), // 이름 없는 튜플 스타일의 필드 i32
}
Message enum의 variant가 갖는 값 또는 구조가 곧 해당 variant의 “필드”입니다. 구조체 스타일인 경우는 필드 개념이 동일하며, 튜플 형식인 경우는 구조체와 달리 필드가 없지만 값이 필드가 됩니다.
enum은 이 필드(데이터) 덕분에, variant별로 타입에 따라 다양한 정보를 유연하게 표현할 수 있습니다.
3. pattern
- 정의: 값을 구조적으로 분해 처리하기 위한 형태. match, let, 함수 매개 변수 등에서 사용합니다.
- 예시:
// struct Point 정의
struct Point {
x: i32,
y: i32,
}
fn main() {
// 튜플 패턴 예제
let (a, b) = (1, 2);
println!("a = {}, b = {}", a, b);
// 구조체 및 구조체 패턴 매칭 예제
let p = Point { x: 10, y: 20 };
match p {
Point { x, y } => println!("({}, {})", x, y),
}
}
- let (a, b) = (1, 2); => 오른쪽 (1, 2)는 타입이 (i32, i32)인 튜플이며, 이 값을 튜플로 받아서, 첫 번째 요소는 변수 a에, 두 번째 요소는 변수 b에 바인딩해줘”라는 뜻입니다.
- match p {
Point { x, y } => println!(“({}, {})”, x, y),
} 에서
Point { x, y }는 매칭 대상(p)이 해당 구조와 일치하는지 검사하고, 일치한다면 그 필드값을 변수로 분해해주는 패턴 역할을 합니다. 따라서 match에서 구조체 내부 값을 분해하고 싶으면 항상 이런 형태의 패턴을 사용하게 됩니다.
4. match arm
- 정의: match 구문의 각분기(패턴 + 처리 블록).
- 예시:
let n = 3;
match n {
1 => println!("One"), // arm 1
2 | 3 | 5 => println!("Prime"), // arm 2
_ => println!("Other"), // arm 3
}
각각이 match arm이며, 패턴과 실행할 코드 블록으로 구성되어 있다.
match arm에서의 패턴(pattern)은, 매칭 대상이 되는 값이 어떤 구조나 값을 가지고 있는지 비교하고, 해당 구조와 일치하면 그 arm의 코드를 실행하도록 하는 역할을 합니다.
즉, match 구문의 각 arm(갈래, 분기)은 패턴 => 실행코드 형태로 이루어지며, 패턴은 값의 형태를 설명하거나 내부 값을 분해하는 구조입니다
4. block
- 정의: 중괄호 {}로 둘러싸인 코드 구역. 블록은 표현식이며 값과 타입을 가진다.
- 예시:
let result = {
let x = 2;
x * x // 마지막 표현식이 결과값이 됨
};
// result = 4
5. scope
- 정의: 변수나 아이템이 유효한 코드의 범위.
- 예시:
fn main() {
let x = 10; // x는 main 함수 블록(scope)에서만 유효
}
가. block과 scope 비교
(1) block
(2) scope
- scope는 어떤 변수(또는 아이템)를 ‘볼 수 있고 사용할 수 있는 코드의 범위’입니다.
- scope는 보통 block에 의해 결정되지만, 완전히 같지는 않습니다.
- 모든 block은 새로운 scope를 열지만,
- scope의 개념은 block 외에도 함수, 모듈, crate 등 더 넓거나 좁게 적용될 수 있습니다.
(3) 차이점 및 예제
- block:
{ ... }
로 감싸진 모든 코드 덩어리를 의미. - scope: 그 안에서 선언된 변수나 아이템이 유효한 코드의 범위.
- 모든 block이 scope를 정의하지만, scope는 더 넓은 개념입니다.
예시:
fn main() { // main 함수 block, 여기가 scope 시작
let outer = 10; // 'outer'의 scope는 main 함수 전체
{ // 새로운 block 시작, 이 안이 block scope
let inner = 20; // 'inner'의 scope는 이 중괄호 안
println!("{}, {}", outer, inner);
} // inner는 여기서 scope 종료
println!("{}", outer); // ok
println!("{}", inner); // 에러, inner는 scope out!
}
여기서 inner는 작은 block(scope)에만 존재.
outer는 main block(scope) 전체에 존재.
6. associated type
- 정의: 트레잇에서 타입 매개변수 대신 트레잇에 연결된 타입을 선언.
- 예시:
trait Iterator {
type Item; // associated type
fn next(&mut self) -> Option<Self::Item>;
}
struct Counter;
impl Iterator for Counter {
type Item = i32;
fn next(&mut self) -> Option<i32> { /* 구현 */ None }
}
Iterator 트레잇에서 Item이 associated type이다.
가. 타입 매개변수와 associated type(연관 타입)의 정의
(1) 타입 매개변수:
- generic에서 사용하는 타입 변수입니다.
- 예: trait MyTrait<T> { … }에서 T가 타입 매개변수입니다.
(2) associated type(연관 타입)
- 트레잇에서 선언해서, 트레잇을 구현할 때 구체적으로 지정하는 타입입니다.
- trait Iterator { type Item; … }에서 Item이 이에 해당.
두 가지의 차이를 간단히 예시로 정리하면:
방법 | 선언 방식 | 사용 예시 | 주의점 |
---|---|---|---|
타입 매개변수 | trait MyTrait<T> { … } | struct Foo; impl MyTrait<u32> for Foo { … } | 사용 때마다 타입 지정 필요 |
associated type | trait MyTrait { type Output; … } | struct Bar; impl MyTrait for Bar { type Output = u32; } | 트레잇 구현이 타입 결정 |
나. 예시
(1) 타입 매개변수(Generic parameter)를 사용하는 트레잇
// 타입 매개변수를 사용하는 트레잇
trait MyTrait<T> {
fn foo(&self, x: T);
}
// 해당 트레잇을 구현하는 타입 예시
struct MyType;
impl MyTrait<i32> for MyType {
fn foo(&self, x: i32) {
println!("MyTrait<i32>::foo called with x = {}", x);
}
}
fn main() {
let t = MyType;
t.foo(100);
}
실행 결과:
MyTrait<i32>::foo called with x = 100
(2) Associated Type(연관 타입)을 사용하는 트레잇 예시
// 연관 타입을 사용하는 트레잇
trait AnotherTrait {
type Output;
fn bar(&self) -> Self::Output;
}
// 해당 트레잇을 구현하는 타입 예시
struct MyType;
impl AnotherTrait for MyType {
type Output = i32;
fn bar(&self) -> i32 {
42
}
}
fn main() {
let t = MyType;
let v: i32 = t.bar();
println!("AnotherTrait::bar returned {}", v);
}
실행 결과:
AnotherTrait::bar returned 42
7. attribute
- 정의: 컴파일러에게 부가 정보를 주는 메타데이터. #[…] 또는 #![…] 형태.
- 예시:
#[derive(Debug)]
struct MyStruct;
#[cfg(target_os = "linux")]
fn linux_only() {}
#[allow(dead_code)]
fn unused_function() {}
주로 코드 자동 생성(derive), 조건부 컴파일(cfg), 경고 제어 등에 사용된다.
attribute에 대해서는 다음 편에서 더 자세히 다룰 예정입니다.