如何使结构可以从元组文字自动转换?

Zom*_*agk 5 struct tuples ios swift

在Swift中,是否可以将某些文字自动转换为其他类型?

let _: Double = 1  // Int literal to Double variable
Run Code Online (Sandbox Code Playgroud)

但是,对于结构,编译器拒绝执行类似的转换:

struct User {
  var id: Int
  var name: String
}

let _: User = (id: 778, name: "Pete")  // error: cannot convert value of type '(id: Int, name: String)' to specified type 'User'
Run Code Online (Sandbox Code Playgroud)

用相应的字段定义一个初始化程序也无济于事。

当从上下文中清除类型时,是否可以忽略结构的显式初始化器?

Lou*_*Lac 4

在 Swift 中,唯一可用于实例化类型的文字是Int, Double, String, Bool, 和Array's 和Dictionary's 。不允许使用元组。

Swift 的目标是成为一种强类型语言,因此您应该使用:

let user = User(id: 778, name: "Pete")

这既明确又简短,并且不会比您正在寻找的内容更冗长。


但是,您可以使任何类型符合任何ExpressibleBy<LiteralType>Literal. 这是一种有趣的方法来实现与元组初始化类似的行为:

struct User {
  var id: Int
  var name: String
}

extension Person: ExpressibleByDictionaryLiteral {
    init(dictionaryLiteral elements: (String, Any)...) {
        let elements = Dictionary(uniqueKeysWithValues: elements)
        self.id = elements["id"]! as! Int
        self.name = elements["name"]! as! String
    }
}

let user: User = ["id": 778, "name": "Pete"]
Run Code Online (Sandbox Code Playgroud)

这既不安全又低效。


一种更安全但不太方便的方法是使用静态工厂方法:

extension User {
    static func t(_ tuple: (Int, String)) -> User {
        User(id: tuple.0, name: tuple.1)
    }
}

let user: User = .t((id: 778, name: "Pete"))
Run Code Online (Sandbox Code Playgroud)

另一个有趣的事情是,在某些上下文中,编译器将允许使用与要使用的初始化程序签名完全匹配的元组,例如在使用时map

let persons = [(id: 778, name: "Pete")]
let users = persons.map(User.init)
Run Code Online (Sandbox Code Playgroud)