Swift Expressible literal

Swift Expressible Literal

引子

從一個面試題說起。有如下程式碼:

struct Book {
    let name: String
}

let book: Book = "Charlotte's Web"

請問是否可以讓它正常編譯?

字面量

字面量指字面代表的常量值。這樣解釋起來有點像廢話。但是通過例子就很容易理解了。

以下是 Swift 中的一些字面量:

種類 示例
字元串 "ich", Bingo!
浮點型數字 1001.3, 33.0
整型數字 1001, 33
布爾值 true, false
數組 ["Emily", "Ben", "Eric"]
字典 ["name": "Ben"]
nil

Expressible Literal 協議

Swift 中,String, Float, Double, IntBool 等類型,和上面的 Book 一樣,都是 struct 。那麼它們是怎麼實現將字面量直接創建實例的呢?以下是 Bool 類型的一個拓展:

extension Bool : ExpressibleByBooleanLiteral {

    /// Creates an instance initialized to the specified Boolean literal.
    ///
    /// Do not call this initializer directly. It is used by the compiler when
    /// you use a Boolean literal. Instead, create a new `Bool` instance by
    /// using one of the Boolean literals `true` or `false`.
    ///
    ///     var printedMessage = false
    ///
    ///     if !printedMessage {
    ///         print("You look nice today!")
    ///         printedMessage = true
    ///     }
    ///     // Prints "You look nice today!"
    ///
    /// In this example, both assignments to the `printedMessage` variable call
    /// this Boolean literal initializer behind the scenes.
    ///
    /// - Parameter value: The value of the new instance.
    public init(booleanLiteral value: Bool)

    /// A type that represents a Boolean literal, such as `Bool`.
    public typealias BooleanLiteralType = Bool
}

再看看 Float 的一個拓展:

extension Float : ExpressibleByIntegerLiteral {

    /// Creates an instance initialized to the specified integer value.
    ///
    /// Do not call this initializer directly. Instead, initialize a variable or
    /// constant using an integer literal. For example:
    ///
    ///     let x = 23
    ///
    /// In this example, the assignment to the `x` constant calls this integer
    /// literal initializer behind the scenes.
    ///
    /// - Parameter value: The value to create.
    public init(integerLiteral value: Int64)

    /// A type that represents an integer literal.
    ///
    /// The standard library integer and floating-point types are all valid types
    /// for `IntegerLiteralType`.
    public typealias IntegerLiteralType = Int64
}

除了 ExpressibleByBooleanLiteralExpressibleByBooleanLiteral 類似的協議還有 ExpressibleByStringLiteral, ExpressibleByNilLiteral, ExpressibleByArrayLiteral 等等。
所以,最開始的那個題目,就有答案了。

注意上面兩個大程式碼塊裡面的注釋,都有一句 Do not call this initializer directly

Tags: