我不知道是否可能,但我认为可以有办法做我想做的事。
我有以下情况:
enum ContactStatus: UInt {
case requestSent = 0, requestReceived, requestProcessing, active, removed
}
struct Contact {
var uid: String
var name: String?
var contactStatus: ContactStatus
init(uid: String, name: String? = nil, contactStatus: ContactStatus = .requestSent) {
self.uid = uid
self.name = name
self.contactStatus = contactStatus
}
}
class ContactStorage: {
private var contacts: [Contact]
init(contacts: [Contact]) {
contacts = contacts
}
func createContact(uid: String, contactStatus status: ContactStatus, name: String?) -> Contact {
var newContact = Contact(uid: uid)
newContact.contactStatus = status
newContact.name = name
newContacts.append(newContact)
return newContact
}
func updateContact(status: ContactStatus, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].contactStatus = status
return
}
}
}
func updateContact(name: String, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].name = name
return
}
}
}
}
我们可以看到,ContactStorage
有两种方法可以更新联系人状态和姓名
我希望使用通用数据类型或任何其他可能的方式合并这两种方法。
类似的东西:
func updateContact<T: Updateable>(peerUId: String, updatableProperty: T) {
//implementation
}
是否可以只编写一种方法而不是两种方法?
答案 0 :(得分:1)
你可以通过闭包来“做到”。
“XXX”和“YYY”部分是您拥有的两种方法之间唯一不同的部分:
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
contacts[index].XXX = YYY
return
}
}
因此,如果我们想要将其作为方法提取,我们需要一个闭包作为参数来提供“XXX”部分。
关闭可能如下所示:
(inout Contact, T) -> Void
对于“YYY”部分,常规参数可以正常运行。
所以,方法如下:
func updateProperty<T>(property: (inout Contact, T) -> Void, value: T, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
property(&contacts[index], value)
return
}
}
}
你会这样称呼:
updateProperty(property: {$0.name = $1}, value: "Tom", peerUId: "something")
另一种方法是完全删除“YYY”,并将其集成到闭包中:
func updateProperty(property: (inout Contact) -> Void, peerUId: String) {
for (index, _) in contacts.enumerated() {
if contacts[index].uid == peerUId {
property(&contacts[index])
return
}
}
}
用法:
updateProperty(property: {$0.name = "Tom"}, peerUId: "something")
答案 1 :(得分:0)
不需要通用功能。您应该让updateContact
有3个输入参数:peerUId
,name
和status
,并将后两个设置为具有nil
默认值的选项。这样,您可以使用单个函数调用更新name
和status
,如果您只想更新其中一个,则不要为另一个指定输入值。
func updateContact(peerUId: String, status: ContactStatus? = nil, name: String? = nil) {
if status == nil, name == nil { return } //wrong function call, return
for i in 0..<contacts.count {
if contacts[i].uid == peerUId {
if let newStatus = status {
contacts[i].contactStatus = newStatus
}
if let newName = name {
contacts[i].name = newName
}
}
}
}
你可以这样调用这个函数:
updateContact(peerUId: "value", status: ContactStatus.active) //only updates the contactStatus
updateContact(peerUId: "value", name: "John") //only updates the name
updateContact(peerUId: "value", status: ContactStatus.active, name: "John") //updates both in a single function call