타입
타입 (Types)
Rust 프로그램의 모든 변수, 항목, 값은 타입을 가져요. 값의 타입은 그 값을 담는 메모리의 해석과 값에 수행할 수 있는 연산을 정의해요. 이번 장에서는 Rust의 타입 체계를 전체적으로 훑어볼게요.
출처: Rust Reference
본문
모든 변수, 항목, 값은 타입을 가져요. 값의 타입은 그 값을 담고 있는 메모리의 해석과 그 값에 수행할 수 있는 연산을 정의해요.
내장(built-in) 타입은 비자명한 방식으로 언어에 긴밀하게 통합되어 있어서, 사용자 정의 타입으로는 흉내낼 수 없는 부분이 많아요. 사용자 정의 타입은 제한된 능력을 가져요.
Rust의 타입 목록은 다음과 같아요:
- 불리언 —
bool - 숫자 — 정수와 실수
- char
- str
- Never 타입 —
!— 값을 하나도 갖지 않는 타입 - 튜플 (Tuple)
- 배열 (Array)
- 슬라이스 (Slice)
- 구조체 (Struct)
- 열거형 (Enum)
- 공용체 (Union)
- 함수 (Functions)
- 클로저 (Closures)
- 참조 (References)
- 원시 포인터 (Raw pointers)
- 함수 포인터 (Function pointers)
- trait 객체 (Trait objects)
- impl trait
타입 표현식 (Type expressions)
Type → TypeNoBounds
| ImplTraitType
| TraitObjectType
TypeNoBounds → ParenthesizedType
| ImplTraitTypeOneBound
| TraitObjectTypeOneBound
| TypePath
| TupleType
| NeverType
| RawPointerType
| ReferenceType
| ArrayType
| SliceType
| InferredType
| QualifiedPathInType
| BareFunctionType
| MacroInvocation
위 Type 문법 규칙에서 정의된 타입 표현식은 타입을 가리키는 구문이에요. 다음을 가리킬 수 있어요:
- 시퀀스 타입(튜플, 배열, 슬라이스).
- 원시 타입(불리언, 숫자,
char,str). - 항목으로의 경로(구조체, 열거형, 공용체, 타입 별칭, trait).
Self가 구현 중인 타입일 때의Self경로.- 제네릭 타입 매개변수.
- 포인터 타입(참조, 원시 포인터, 함수 포인터).
- 컴파일러가 타입을 결정하도록 요청하는 추론된 타입.
- 모호성 해소에 쓰이는 괄호.
- trait 타입: trait 객체와 impl trait.
- never 타입.
- 타입 표현식으로 확장되는 매크로.
괄호로 감싼 타입 (Parenthesized types)
ParenthesizedType → ( Type )
어떤 상황에서는 타입의 조합이 모호할 수 있어요. 그럴 때는 타입 주위에 괄호를 써서 모호성을 피해요. 예를 들어 참조 타입 안에서 타입 바운드의 + 연산자가 어디에 적용되는지 불분명할 때 괄호 사용이 필요해요. 이렇게 모호성 해소가 필요한 문법 규칙은 Type 대신 TypeNoBounds 규칙을 사용해요.
#![allow(unused)]
fn main() {
use std::any::Any;
type T<'a> = &'a (dyn Any + Send);
}
재귀 타입 (Recursive types)
명목적(nominal) 타입 — 즉 구조체, 열거형, 공용체 — 은 재귀적일 수 있어요. 즉 각 열거형 변형이나 구조체·공용체 필드가, 직접적으로든 간접적으로든 그것을 감싸는 열거형이나 구조체 타입 자신을 가리킬 수 있어요.
이런 재귀에는 제약이 있어요:
- 재귀 타입은 재귀에 명목적 타입을 포함해야 해요. (단순한 타입 별칭이나 배열·튜플 같은 다른 구조적 타입이 아니라.) 그래서
type Rec = &'static [Rec]는 허용되지 않아요. - 재귀 타입의 크기는 유한해야 해요. 다시 말해 재귀 필드는 포인터 타입이어야 해요.
재귀 타입과 그 사용 예시예요:
#![allow(unused)]
fn main() {
enum List<T> {
Nil,
Cons(T, Box<List<T>>)
}
let a: List<i32> = List::Cons(7, Box::new(List::Cons(13, Box::new(List::Nil))));
}
더 알아보기 (Learn more)
- 각 타입의 상세 규칙은 The Rust Reference의 타입별 챕터(숫자, 튜플, 배열, 슬라이스, 함수, 참조 등)에서 다뤄요.
- 재귀 타입과 DST의 관계는 동적 크기 타입 챕터를 함께 보면 좋아요.