ios - 符合通用协议(protocol)的结构类型,其关联类型也是协议(protocol)

标签 ios swift generics protocols

这很难用语言表达,但我创建了一个最小的示例。

这里有一个要点,如果您愿意... https://gist.github.com/anonymous/67d83fb2f286cf84539b58be96a971d3

“数据项”协议(protocol)

我有一个协议(protocol),它定义了具有属性 numberSortable 对象。

protocol Sortable: Comparable {
    var number: Int {get}

    static func < (lhs:Self, rhs: Self) -> Bool
    static func == (lhs:Self, rhs: Self) -> Bool
}

struct BasicSortable: Sortable {
    let number: Int

    static func < (lhs:BasicSortable, rhs: BasicSortable) -> Bool {
        return lhs.number < rhs.number
    }

    static func == (lhs:BasicSortable, rhs: BasicSortable) -> Bool {
        return lhs.number == rhs.number
    }
}

“ worker ”协议(protocol)

然后我有一个协议(protocol)可以对这些 Sortable 类型做一些事情。但是因为它有一个 Self 要求,它需要被定义为一个具有关联类型的协议(protocol),并在结构中作为通用属性...

protocol Sorter {
    associatedtype Item: Sortable

    func sort(items: [Item]) -> [Item]
}

// Two different sorters
struct AscendingSorter<T:Sortable>: Sorter {
    typealias Item = T

    func sort(items: [T]) -> [T] {
        return items.sorted()
    }
}

struct DescendingSorter<T:Sortable>: Sorter {
    typealias Item = T

    func sort(items: [T]) -> [T] {
        return items.sorted{$0 > $1}
    }
}

处理程序

最后是一个将所有内容组合在一起的结构......

struct DataHandler<T: Sortable> {
    let items: [T]
    let sortedItems: [T]

    init(unsortedItems: [T]) {
        items = unsortedItems

        let sorter = AscendingSorter<T>()
        sortedItems = sorter.sort(items: unsortedItems)
    }
}

让一切正常运转

一切正常。

let array = [
    BasicSortable(number: 1),
    BasicSortable(number: 8),
    BasicSortable(number: 13),
    BasicSortable(number: 3),
    BasicSortable(number: 4),
    BasicSortable(number: 14),
    BasicSortable(number: 5),
    BasicSortable(number: 12),
    BasicSortable(number: 3),
]

let handler = DataHandler(unsortedItems: array)

handler.sortedItems

这会根据我在 Handler 中创建的排序器类型以正确的顺序打印出项目数组

问题

我现在想做的是为这个 sorter 结构找到一个属性声明,它可以将任何 Sorter 类型放入其中,但到目前为止我所做的一切尝试都失败了。

有办法吗?

在我想要的结构中......

let sorter: SomeTypeHere

然后在初始化中将其设置为...

sorter = AscendingSorter()

但我尝试过的组合都没有奏效。

谢谢

最佳答案

您可以使用类型删除来实现您自己的 AnySorter .

从上面的你自己的代码开始:

protocol Sortable: Comparable {
    var number: Int {get}

    /* as Hamish mentions in his answer: 
       < and == already blueprinted in Comparable and Equatable */
}

protocol Sorter {
    associatedtype Item: Sortable

    func sort(items: [Item]) -> [Item]
}

构造一个 AnySorter :

struct AnySorter<Item: Sortable>: Sorter {
    private let _sort: ([Item]) -> [Item]

    init<S: Sorter where S.Item == Item>(_ sorter: S) {
        _sort = sorter.sort
    }

    func sort(items: [Item]) -> [Item] {
        return _sort(items)
    }
}

你使用的,例如作为 DataHandler 中初始值设定项的参数:

struct DataHandler<T: Sortable> {
    let items: [T]
    let sortedItems: [T]

    init(unsortedItems: [T], sorter: AnySorter<T>) {
        items = unsortedItems
        sortedItems = sorter.sort(items: unsortedItems)
    }
}

您的处理程序现在可以与已删除的类型一起使用 AnySorter适用于您的 Sortable类型。例如,对于您在问题中提供的两个简单分类器:

struct AscendingSorter<T:Sortable>: Sorter {
    typealias Item = T

    func sort(items: [T]) -> [T] {
        return items.sorted()
    }
}

struct DescendingSorter<T:Sortable>: Sorter {
    typealias Item = T

    func sort(items: [T]) -> [T] {
        return items.sorted{$0 > $1}
    }
}

/* example usage */ 
extension Int: Sortable {
    var number: Int { return self }
} 

let arr = [1, 4, 2, 8, 3]

let dataHandlerDesc = DataHandler(unsortedItems: arr, sorter: AnySorter(DescendingSorter()))
print(dataHandlerDesc.sortedItems) // [8, 4, 3, 2, 1]

let dataHandlerAsc = DataHandler(unsortedItems: arr, sorter: AnySorter(AscendingSorter()))
print(dataHandlerAsc.sortedItems) // [1, 2, 3, 4, 8]

编辑添加以回答您的评论:

Is it possible to take the input parameter and store it in a property? Would I just use AnySorter<T> as the type of the property?

是的,您可以在 DataHandler 中保留属性(property)与类型 AnySorter .例如,对于一个人为的例子,我们可以让 sortedItems是一个使用 AnySorter 的计算属性对存储的项目列表进行排序的实例(当然,实际上我们不想为每次调用都重新排序,但仅针对此示例!):

struct DataHandler<T: Sortable> {
    let items: [T]
    var sortedItems: [T] { return sorter.sort(items: items) }
    var sorter: AnySorter<T>

    init(unsortedItems: [T], sorter: AnySorter<T>) {
        items = unsortedItems
        self.sorter = sorter
    }

    mutating func changeSorter(newSorter: AnySorter<T>) {
        sorter = newSorter
    }
}

/* example usage */ 
extension Int: Sortable {
    var number: Int { return self }
} 

let arr = [1, 4, 2, 8, 3]

var dataHandler = DataHandler(unsortedItems: arr, sorter: AnySorter(DescendingSorter()))
print(dataHandler.sortedItems) // [8, 4, 3, 2, 1]

dataHandler.changeSorter(newSorter: AnySorter(AscendingSorter()))
print(dataHandler.sortedItems) // [1, 2, 3, 4, 8]

关于ios - 符合通用协议(protocol)的结构类型,其关联类型也是协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39477873/

相关文章:

swift - 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序,原因 : '-[__NSCFData earlierDate:]

swift - Swift 中的核心数据同步

scala - 什么是节点 [TypeOne < : Node[TypeOne]] in scala mean?

java - 使用泛型改进类

ios - 表格 View 中的图像在选择时会更改大小

iOS UISlider - 更改价格值

iphone - iOS:viewDidLoad 中的 View 高度设置不正确

ios - 使用 Autoshrink 调整 UILabel 文本

ios - 如何在列表中搜索具有特定属性的对象的索引?

java - 如何在 java 中创建固定大小的通用缓冲区?