Swift

Literal 이란?

Phililip 2022. 2. 7.
728x90

ExpressibleByStringLiteral 프로토콜이 뭔지 궁금해서 공부하던 중,

 

ExpressibleBy...Literal 프로토콜을 알려면 Literal이 뭔지 알아야 하겠더라구요...

 

그래서 이번 글에서는 Literal이 뭔지 우선 알아보고, 그다음에 ExpressibleBy...Literal 프로토콜도 살펴보겠습니다.

 

#1 Literal

공식 Swift 문서를 토대로 이해한 내용을 적어보겠습니다.

 

Literal이란, value 타입의 소스 코드 표현입니다.

 

아래를 보면 42, 3.14159, "Hello, world!"가 Literal입니다.

42               // Integer literal
3.14159          // Floating-point literal
"Hello, world!"  // String literal
true             // Boolean literal

 

하지만 Literal은 타입을 가지지 않습니다.

 

즉, 위에서 말한 42는 Int 형이 아닌 그냥 Integer literal이라는 의미입니다.

 

대신에 Swift는 Literal을 보고 타입을 결정합니다.

 

예를 들어

let x: Int 8 = 42

위 코드처럼 Int8이라고 타입을 명시적으로 선언했을 경우, 42(integer literal)의 타입을 Int8이라고 추론하는 것이죠.

 

만약 타입을 명시적으로 선언한 것이 아니라면, Swift는 literal의 default type을 보고 타입을 결정하게 됩니다.

 

 

let x = 42

즉, 위 코드의 경우, x의 타입은 integer literal의 default type인 Int형이 됩니다.

 

 

 

각 Literal 마다 default type은 아래와 같습니다.

integer literals -> Int
floating-point literals -> Double
string literals -> String
Boolean literals -> Bool
...

 

 

 

근데.. integer literal의 default type은 Int형인데 어떻게 타입을 명시적으로 선언한다고 해서 Int -> Int8로 타입을 바꿀 수 있었을까요?

 

이때 사용한 것이 ExpressibleBy...Literal 프로토콜 입니다.

 

#2 ExpressibleBy...Literal 프로토콜

literal을 특정 타입으로 지정하고 싶을 때 ExpressibleBy...Literal 프로토콜을 사용합니다.

 

literal과 마찬가지로 ExpressibleBy...Literal 종류도 다양합니다.

ExpressibleByIntegerLiteral
ExpressibleByFloatLiteral
ExpressibleByStringLiteral
ExpressibleByBooleanLiteral
...

 

 

 

즉, Int8은 ExpressibleByIntegerLiteral 프로토콜을 준수하고 있었던 것이고, 그로 인해 integer literal 42의 타입을 Int8로 유추할 수 있었던 것이었습니다. 오호.....

 

그럼 ExpressibleBy...Literal 프로토콜을 사용하면 커스텀 타입으로 유추하도록 할 수도 있겠네요!

 

#3 커스텀 타입으로 유추시키기

일단 Person이라는 구조체를 만들어볼게요.

struct Person {
    let age: Int
}

 

 

별도의 생성자를 만들어주지 않아도 Swift는 자동으로 생성해주기 때문에 아래처럼 사용할 수 있어요.

let philip: Person = Person(age: 19)

 

 

이번에는 literal을 가지고 타입을 유추시키기 위해서 ExpressibleByStringLiteral 프로토콜을 준수하도록 수정해볼게요.

struct Person: ExpressibleByStringLiteral {
    let age: Int
}

 

 

이대로 끝!.... 하고 싶지만 ExpressibleByStringLiteral 프로토콜을 준수하려면 required initializer를 꼭 구현하셔야 합니다.
(ExpressibleByStringLiteral 뿐만 아니라 ExpressibleBy...Literal 프로토콜을 사용한다면 꼭 지켜주셔야 해요.)

 

 

 

init(stringLiteral:) method를 구현해줍니다.

struct Person: ExpressibleByStringLiteral {
    let age: Int
    
    init(stringLiteral value: StringLiteralType) {
        age = Int(value)!
    }
}

이제 진짜 끝입니다!!

 

ExpressibleByStringLiteral 프로토콜을 준수해서 아래처럼 커스텀 타입을 지정해줄 수 있습니다.

let philip: Person = "19"        // philip.age = 19

 

물론 ExpressibleBy...Literal 프로토콜을 여러 개 준수하게끔 구현할 수도 있어요.

struct Person: ExpressibleByStringLiteral, ExpressibleByIntegerLiteral {
    let age: Int
    
    init(stringLiteral value: StringLiteralType) {
        age = Int(value)!
    }

    init(integerLiteral value: IntegerLiteralType) {
        age = value
    }
}

let philip: Person = "19"	// philip.age = 19
let kiki: Person = 29		// kiki.age = 29

 

다만... required initializer 때문에 생성자를 직접 구현해서 사용하는 것이라,

 

Swift가 자동으로 생성해주는 생성자는 사용할 수 없습니다...ㅠㅠ

let philip: Person = Person(age: 19)    // error : Incorrect argument label in call (have 'age:', expected 'integerLiteral:')

 

반응형