【问题标题】:Using append in generic function inside Array extension在 Array 扩展内的泛型函数中使用 append
【发布时间】:2015-05-26 09:09:32
【问题描述】:

在 Array 扩展中创建泛型函数时,我发现了这个晦涩的问题。假设我有用于创建数组的 User 类:

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 或 User 的任何其他子类的函数的 Array 扩展,它将一些测试用户添加到任何用户数组。我把它写在扩展中而不是我自己的类型的原因是因为我想使用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)
    }
}

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

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

我知道这是因为从未将扩展名指定为用户数组的扩展名,但正如我所见,我无法做到这一点。

【问题讨论】:

标签: ios swift generics


【解决方案1】:

正如@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]
}

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多