Swift protocol 系列之 ExpressibleByXXXLiteral协议簇(字面量)

「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战」。

Swift 的一个特性就是ExpressibleBy-Literal协议簇(字面量)。这是一组协议,允许您通过提供一些Swift 对象来实例化对象。例如,我们可以实例化一个提供布尔值或字符串的对象。Literal是表示源代码中固定值的符号。整数、字符串、布尔值、浮点数、数组、字典都是Literal ,就像实例Array数组字面量(*array literal*)是两个不同的东西,不应该混淆。对于Dictionary也是同样的原因。

Swift 包含一系列ExpressibleByLiteral协议,用于使用匹配的文字初始化自定义类型。

字面量

字面量指字面代表的常量值。

种类 示例
字符串 "joke"hello world
浮点型数字 100.3
整型数字 103
布尔值 truefalse
数组 [1, 2, 3]
字典 ["name": "joke"]
nil

ExpressibleByNilLiteral

ExpressibleByNilLiteral是当一个对象被初始化时nil,您不希望整个对象为零,您可能有一个自定义要求,您需要考虑在其中的属性nil显示不同的内容。但是Apple不鼓励遵循ExpressibleByNilLiteral自定义类型。目前只有Optional类型符合它,用于表示没有值。

struct XWNilTest {
  var name: String?
  var sex: String?
}

extension XWNilTest: ExpressibleByNilLiteral{
     init(nilLiteral: ()) {
       self.name = "Joke"
       self.sex = "男"
    }
}

let myStruct: XWNilTest = nil
print(myStruct.name)//XWNilTest(name: Optional("Joke"), sex: Optional("男"))
复制代码

ExpressibleByStringLiteral

ExpressibleByStringLiteral可以使用字符串来实例化我们的对象。StringStaticString类型符合ExpressibleByStringLiteral协议,使用此协议时,请确保至少实现以下init(stringLiteral:)方法:

extension URL : ExpressibleByStringLiteral {
    public init(stringLiteral value: StringLiteralType) {
        guard let url = URL(string: "\(value)") else {
            preconditionFailure("This url: \(value) is not invalid")
        }
        self = url
    }
}

let url : URL = "https:www.xxx.com"
print(url)//https:www.xxx.com
复制代码

ExpressibleByIntegerLiteral

ExpressibleByIntegerLiteral使用数字来实例化我们的对象非常容易。使用此协议时,请确保至少实现以下init(integerLiteral:)方法:

extension Date: ExpressibleByIntegerLiteral {
    public init(integerLiteral value: Int) {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        self = formatter.date(from: String(value)) ?? Date()
    }
}

let date : Date = 19941221
print(date)//**1994-12-20 16:00:00 +0000**
复制代码

ExpressibleByFloatLiteral

标准库浮点类型——FloatDouble都符合ExpressibleByFloatLiteral协议。您可以通过分配浮点文字来初始化任何这些类型的变量或常量。

struct XWFloatTest: ExpressibleByFloatLiteral {
    let value: Float
    typealias FloatLiteralType = Float
    init(floatLiteral value: Float) {
        self.value = value
    }
}

let  num: XWFloatTest = 5.5
print(num)//**WFloatTest(value: 5.5)**
复制代码

ExpressibleByBooleanLiteral

可以用布尔值初始化true并且false应该符合这个协议的类型。

struct XWBoolTest: ExpressibleByBooleanLiteral {

  typealias BooleanLiteralType = Bool
  let boolValue: Bool
   init(booleanLiteral value: BooleanLiteralType) {
     self.boolValue = value
  }
}

let  isSucc: XWBoolTest = false
print(isSucc)
复制代码

ExpressibleByArrayLiteral

ExpressibleByArrayLiteral遵守协议时实现由Array支持的自定义集合。

class XWArrayTest: ExpressibleByArrayLiteral {
  public typealias ArrayLiteralElement = Int
  let numbers: [ArrayLiteralElement]

  public required init(arrayLiteral elements: ArrayLiteralElement...){
    self.numbers = elements.map { $0 * $0 }
  }
}

let  array: XWArrayTest =  [2, 4, 6]
print(array.numbers)//**[4, 16, 36]**
复制代码

ExpressibleByDictionaryLiteral

与其对应的 Array 类似,ExpressibleByDictionaryLiteral主要用于由字典支持的自定义集合和类型。

struct HTTPHeaders {
    private let headers: [String: String]
}

extension HTTPHeaders: ExpressibleByDictionaryLiteral {

    init(dictionaryLiteral elements: (String, String)...) {
        var headers: [String: String] = [:]
        for pair in elements {
            headers[pair.0] = pair.1
        }
        self = HTTPHeaders(headers: headers)
    }
}

let headers: HTTPHeaders = ["Content-Type": "application/json"]
print(headers)//**HTTPHeaders(headers: ["Content-Type": "application/json"])**
复制代码

需要注意的是不应该将DictionaryLiteral与 Dictionary 的实例混淆。因此,不可能通过为其ExpressibleByDictionaryLiteral分配 Dictionary 实例来初始化符合的类型。下面的代码是错误的:

let headersDictionary = ["Content-Type": "application/json"]
let anotherHeaders: HTTPHeaders = headersDictionary
//Cannot convert value of type '[String : String]' to specified type 'HTTPHeaders'
复制代码

Guess you like

Origin juejin.im/post/7034163831622336549