在Array扩展中使用append in generic function

时间:2015-05-26 09:09:33

标签: ios swift generics

在Array扩展中创建泛型函数时,我发现了这个模糊的问题。让我们说我有用于创建数组的用户类:

class User : NSObject {
    let name : String
    let surname : String

    init(name : String, surname : String) {
        self.name = name
        self.surname = surname
    }

    override var description : String {
        return self.name + " " + self.surname
    }
}

请注意,我需要它作为NSObject的子类。现在让我们创建两个用户并将其添加到用户数组中。

var user1 = User(name: "Jimmy", surname: "Page")
var user2 = User(name: "David", surname: "Guilmour")

var users = Array<User>()
users.append(user1)
users.append(user2)

现在我需要一个具有特定于Array的函数的Array扩展,或者User的任何其他子类,它将向一些用户数组添加一些测试用户。我在扩展名中写的原因而不是我自己的类型是因为我想使用if let something = something as [User]来检查它的类型。如果我建立自己的类型,我将无法做到这一点。

extension Array {
    mutating func addTestUsers<T : User>() {
        var testUser1 = User(name: "King", surname: "Brown")
        var testUser2 = User(name: "Carlos", surname: "Santana")
        self.append(testUser1)
        self.append(testUser2)
    }
}

当使用追加函数或任何其他可能以某种方式改变初始数组的函数时,会出现问题。

错误:Cannot invoke append with argument list of type (User)

我知道这是因为扩展永远不会被指定为用户数组的扩展,但正如我所看到的,我无法做到这一点。

1 个答案:

答案 0 :(得分:0)

正如@Martin R的评论中所建议的那样,如果你看一下Array extension to remove object by value,那么最高的投票回答建议写一个以数组为参数的函数,在你的情况下你可以这样做:

func addTestUsers(inout array: [User]) {
    let user1 = User(name: "King", surname: "Brown")
    let user2 = User(name: "Carlos", surname: "Santana")
    array += [user1, user2]
} 

然后您可以像这样使用它:

var array = [User(name: "Jimmy", surname: "Page")]
addTestUsers(&array) // [Jimmy Page, King Brown, Carlos Santana]

但是,如果您打算创建User的子类,则之前的方法是不合适的,因为您将无法传递子类数组作为参数。在这种情况下,您可以覆盖addTestUsers以接受您的子类,但更优雅的解决方案可能是:

func addTestUsers<T: User>(inout array: [T]) {
    let user1 = T(name: "King", surname: "Brown")
    let user2 = T(name: "Carlos", surname: "Santana")
    array += [user1, user2]
}

要使上一个功能正常工作,您需要将init(name : String, surname : String)中的User标记为required

class User : NSObject {
    // ... 
    required init(name : String, surname : String) {
        self.name = name
        self.surname = surname
    } 
    // ... 
}

将其标记为required表示User 的任何子类必须实施init(name : String, surname : String),因此在T(name: "...", surname: "...")中使用addTestUsers是安全的}。