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: