Rust의 특별한 용어 정리

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)에서만 유효
}

scope이 끝나면 변수는 더 이상 쓸 수 없다.

가. block과 scope 비교

(1) block

  • 코드에서 중괄호 {}로 둘러싸인 부분 자체를 block이라고 합니다.
  • 예시:rust{ let a = 1; println!("{a}"); }
  • 이 부분 전체가 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 typetrait 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에 대해서는 다음 편에서 더 자세히 다룰 예정입니다.