有没有办法引用类型的构造函数?
Is there a way to reference the constructor of a type?
在Swift中你可以引用一个函数,给它赋值,然后再使用它。我们都知道。但我想知道我们是否可以使用初始化器来做到这一点。这是一些示例代码。假设我有一个 User
结构:
struct User {
let name: String
let age: UInt
init(name: String) {
self.name = name
age = 0
}
}
我有一个名字数组
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
我想将这些名称映射到 User
个实例。我可以这样做:
let users = map(names, { User(name: [=12=]) })
虽然这看起来不错,但我觉得使用 map
函数采用的闭包是不必要的。我的意思是它基本上需要一个名字并产生 User
。但是我们在 User
结构的构造函数中定义了它。为什么我们需要重复它?有没有办法将构造函数作为函数获取并将其直接传递给 map
函数?
如果你只是想避免重复,你可以通过在参数前面加上下划线 _ 来跳过命名参数。
struct User {
let name: String
let age: UInt
init(_ name: String) {
self.name = name
age = 0
}
init(_ name: String, _ age : UInt) {
self.name = name
self.age = age
}
}
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
let users = map(names, {User([=10=])})
简短回答:不,您不能将 init
引用为独立函数。不过还是不错的。
您可以像这样访问成员函数:
extension User {
func getName() -> String { return name }
}
// will be a function that takes a User object,
// and returns a new function that is getName
// called on that object:
let f = User.getName
let u = User("Fred")
// g will be a function that calls getName on u
let g = f(u)
g() // returns "Fred"
如果 User
是 class 而不是结构,您也可以这样做:
// h will be equivalent to g above...
let h = u.getName
h() // returns "Fred"
调用 init
感觉应该更像后者,因为它创建新对象而不是获取现有对象。 User.init
应该 return 一个函数,它接受一个名字并且 return 是一个 User
(尽管你有两个初始化器所以你需要提供一些类型上下文)。但是 Swift 不会让你这样做(告诉你“没有参数就不能引用初始化程序”)。
一件有趣的事情是协议可能需要某些类型的初始化程序,因此您可以执行以下(相当愚蠢的)操作来伪造一个初始化任何类型的函数,仅供娱乐而不是实际使用:
protocol StringInitializable {
init(_ s: String)
}
// no implementation needed as User already conforms
extension User: StringInitializable { }
func initerFromString<T: StringInitializable>(s: String) -> T {
return T(s)
}
let users: [User] = map(names, initerFromString)
上面使用 users
数组的类型修复了类型,但您可以通过修复函数的类型来实现:
let userInit: String->User = initerFromString
let moreUsers = map(names, userInit)
struct Monster: StringInitializable {
let name: String
init(_ name: String) { self.name = name }
}
let monsterInit: String->Monster = initerFromString
let monsters = map(names, monsterInit)
(这个实际用到实际效果的地方在ExtensibleCollectionType
)
在Swift中你可以引用一个函数,给它赋值,然后再使用它。我们都知道。但我想知道我们是否可以使用初始化器来做到这一点。这是一些示例代码。假设我有一个 User
结构:
struct User {
let name: String
let age: UInt
init(name: String) {
self.name = name
age = 0
}
}
我有一个名字数组
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
我想将这些名称映射到 User
个实例。我可以这样做:
let users = map(names, { User(name: [=12=]) })
虽然这看起来不错,但我觉得使用 map
函数采用的闭包是不必要的。我的意思是它基本上需要一个名字并产生 User
。但是我们在 User
结构的构造函数中定义了它。为什么我们需要重复它?有没有办法将构造函数作为函数获取并将其直接传递给 map
函数?
如果你只是想避免重复,你可以通过在参数前面加上下划线 _ 来跳过命名参数。
struct User {
let name: String
let age: UInt
init(_ name: String) {
self.name = name
age = 0
}
init(_ name: String, _ age : UInt) {
self.name = name
self.age = age
}
}
let names = ["Cooper", "Murph", "Brand", "Dr. Mann"]
let users = map(names, {User([=10=])})
简短回答:不,您不能将 init
引用为独立函数。不过还是不错的。
您可以像这样访问成员函数:
extension User {
func getName() -> String { return name }
}
// will be a function that takes a User object,
// and returns a new function that is getName
// called on that object:
let f = User.getName
let u = User("Fred")
// g will be a function that calls getName on u
let g = f(u)
g() // returns "Fred"
如果 User
是 class 而不是结构,您也可以这样做:
// h will be equivalent to g above...
let h = u.getName
h() // returns "Fred"
调用 init
感觉应该更像后者,因为它创建新对象而不是获取现有对象。 User.init
应该 return 一个函数,它接受一个名字并且 return 是一个 User
(尽管你有两个初始化器所以你需要提供一些类型上下文)。但是 Swift 不会让你这样做(告诉你“没有参数就不能引用初始化程序”)。
一件有趣的事情是协议可能需要某些类型的初始化程序,因此您可以执行以下(相当愚蠢的)操作来伪造一个初始化任何类型的函数,仅供娱乐而不是实际使用:
protocol StringInitializable {
init(_ s: String)
}
// no implementation needed as User already conforms
extension User: StringInitializable { }
func initerFromString<T: StringInitializable>(s: String) -> T {
return T(s)
}
let users: [User] = map(names, initerFromString)
上面使用 users
数组的类型修复了类型,但您可以通过修复函数的类型来实现:
let userInit: String->User = initerFromString
let moreUsers = map(names, userInit)
struct Monster: StringInitializable {
let name: String
init(_ name: String) { self.name = name }
}
let monsterInit: String->Monster = initerFromString
let monsters = map(names, monsterInit)
(这个实际用到实际效果的地方在ExtensibleCollectionType
)