有没有办法引用类型的构造函数?

时间:2015-01-04 14:16:06

标签: function swift constructor

在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: $0) })

虽然这似乎很好,但我觉得使用map函数所需的闭包是不必要的。我的意思是它基本上取名并生成User。但是我们在User struct的构造函数中定义了它。为什么我们需要重复它?有没有办法将构造函数作为函数并将其直接传递给map函数?

2 个答案:

答案 0 :(得分:2)

简短回答:不,你不能将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是一个不是结构的类,你也可以这样做:

// h will be equivalent to g above...
let h = u.getName
h()  // returns "Fred"

调用init感觉它应该更像后者,因为它创建了新鲜的对象而不是现有的对象。 User.init应该返回一个带有名称并返回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

答案 1 :(得分:0)

如果您只是想避免重复,可以通过在参数前放置下划线_来跳过给出命名参数。

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($0)})
相关问题