Swift

Literal 이란?

Phililip
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:')

 

반응형