【问题标题】:Is there a way to set the data type of the protocol in function pointer?有没有办法在函数指针中设置协议的数据类型?
【发布时间】:2019-04-09 18:37:06
【问题描述】:

有没有办法在swift的函数指针中设置协议的数据类型?

这是我的协议ICRUDOperation

public protocol ICRUDOperation {
    associatedtype T
    func insert(data:T)
    func update(data:T)
    func get(data:T) -> [T]
    func getList(data: BaseModel) -> [T]
    func getPage(data: BaseModel) -> [T]
    func delete(data: T)
}

我尝试使用的:

func delegate1<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
    sqlite.insert(data: data)
}
var decision = [String : [String:((ICRUDOperation, ICRUDOperation, T) ->())?]]()

func fillDecision() {
    decision["Person"]?["1"] = Delegate1
}

我在决定中遇到此错误

Protocol 'ICRUDOperation' can only be used as a generic constraint because it has Self or associated type requirements

fillDecision() 出错:

Cannot assign value of type '(_, _, _.T) -> ()' to type '((ICRUDOperation, ICRUDOperation, _) -> ())??'

【问题讨论】:

  • 我将函数名和大多数变量名中的前导大写字母改为小写,这是 Swift 标准,以提高可读性

标签: swift types protocols


【解决方案1】:

添加关联类型后,就不再有“ICRUDOOperation”之类的东西了。 PAT(具有关联类型的协议)没有存在形式;它的存在是为了将方法附加到 other 类型,或者限制可以将哪些具体类型传递给泛型函数。您不能将 PAT 存储在变量或字典或其他任何地方。协议(以及双重的 PAT)不是抽象类。

要了解的最关键的一点是,关联类型是由实现 选择的,而不是由调用者选择的。因此,在您的示例中,T 将由 ICRUDOperation 的实现选择(与 Array 选择其 Collection.Index 为 Int 的方式相同;您无法选择它)。泛型允许 调用者 选择类型,这看起来更像您想要实现的目标。

如何解决这个问题取决于您的用例,从您的示例中很难理解。 decision的目标是什么?

如果您能展示您所期望的两个或三个不同的 ICRUDOperation 实现会是什么样子,将会很有帮助。我不确定你想要“操作的实现”是什么意思。

【讨论】:

    【解决方案2】:

    我正在尝试了解您想如何使用它,所以这是我对如何使用该协议的想法。我不确定这是否能回答您的问题,但也许它可以帮助您更接近解决方案。
    假设我们有想要坚持的模型

    struct Item {
        var id: Int
        var name: String
    }
    

    那么我们需要一个可以执行数据库操作的处理程序

    struct ItemDbHandler: ICRUDOperation {
        typealias T = Item
    
        func insert(data: Item) {
            print("\(#function) \(item)")
        }
    
        func update(data: Item) {
            print("\(#function) \(item)")
        }
    
        func get(data: Item) -> [Item] { //shouldn't this return 1 element
            print("\(#function) \(item)")
            return []
        }
        // and so on...
    }
    

    还有一些委托功能

    func delegateUpdate<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
        sqlite.update(data: data)
    }
    

    我们可以直接使用处理程序,也可以通过函数使用

    var item = Item(id: 1, name: "ABC")
    var handler = ItemDbHandler()
    handler.insert(data: item)
    item.name = "abc"
    
    delegateUpdate(sqlite: handler, service: handler, data: item)
    

    在操场上运行它会产生

    插入(数据:)项目(id:1,名称:“ABC”)
    更新(数据:)项目(id:1,名称:“abc”)

    我不明白你想做什么fillDecision,所以我暂时跳过了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 1970-01-01
      • 2018-02-01
      • 1970-01-01
      相关资源
      最近更新 更多