NeuroWhAI의 잡블로그
[Rust] enum 사용시 주의 사항 본문
코드 출처 : https://dtolnay.github.io/rust-quiz/7
#[repr(u8)]
enum Enum {
First,
Second,
}
impl Enum {
fn p(self) {
match self {
First => print!("1"),
Second => print!("2"),
}
}
}
fn main() {
Enum::p(unsafe {
std::mem::transmute(1u8)
});
}
위 코드는 UB인가? 컴파일이 되는가? 된다면 출력은?
(정답은 아래에)
정답은 UB가 아니고 컴파일 되며 출력은 1입니다.
설명이야 위 링크에 잘 나와있지만 정리할겸 적어봅니다.
일단 `#[repr(u8)]` 덕분에 Enum::First == 0u8, Enum::Second == 1u8이 보장된다고 합니다.
어? 그러면 출력은 Second에 해당하는 print 결과인 "2"가 나와야 하는게 아닌가? 싶지만 속임수가 있었습니다.
위 코드를 실행해보면 경고이자 힌트가 여러개 나오는데 주목할 부분이 있습니다.
warning: unreachable pattern --> src/main.rs:11:13 | 10 | First => print!("1"), | ----- matches any value 11 | Second => print!("2"), | ^^^^^^ unreachable pattern | = note: #[warn(unreachable_patterns)] on by default warning: unused variable: `First` --> src/main.rs:10:13 | 10 | First => print!("1"), | ^^^^^ help: consider using `_First` instead | = note: #[warn(unused_variables)] on by default warning: unused variable: `Second` --> src/main.rs:11:13 | 11 | Second => print!("2"), | ^^^^^^ help: consider using `_Second` instead
'unreachable pattern'이라니 이상하죠? 왜 Second에 도달하지 못한다는 것일까요?
self가 First가 아니라면 Second에 매치 될 수 있는데 말이죠.
그 아래의 'unused variable'를 봅시다.
잠깐, variable이라고요?
우리가 쓴 First, Second는 enum의 variant일텐데요?
그렇습니다.
컴파일러가 저걸 변수 선언으로 인식한겁니다.
속임수를 제거하자면 아래와 같은 코드가 됩니다.
impl Enum {
fn p(self) {
match self {
aaa => print!("1"),
bbb => print!("2"),
}
}
}
이러니 두번째 패턴에는 도달하지 못하는 것이었습니다.
그냥 aaa라는 변수를 만들어 self를 할당하는 꼴이고 그러하니 aaa를 안썼다는 경고가 뜨는 것이죠.
무조건 매치되는 패턴입니다.
이 문제를 해결하려면 아래와 같이 해야합니다.
match self {
Enum::First => print!("1"),
Enum::Second => print!("2"),
}
이러면 출력은 "2"가 나옵니다.
혹은 아래 코드를 추가하면 First, Second를 올바르게 variant로 인식합니다.
use Enum::*;
표준의 몇몇 enum들(Result, Option 등)은 위 조치가 취해져 있기 때문에 그냥 Ok(x), None 이렇게 쓸 수 있는 것이었습니다.
'개발 및 공부 > 언어' 카테고리의 다른 글
[Rust] macro_use 불필요! (0) | 2018.12.28 |
---|---|
[Rust] wrapping으로 오버플로/언더플로 에러 피하기 (0) | 2018.12.19 |
[Rust] Lifetime의 한계 (0) | 2018.11.18 |
[C++] Designated initializers (0) | 2018.11.17 |
[C++] get/return_temporary_buffer, uninitialized_*에 대하여 (0) | 2018.11.14 |
Comments