ios – 符合通用协议的结构类型,其关联类型也是协议

这很难说,但我已经创建了一个最小的例子.

如果你更喜欢……这是一个要点

“数据项”协议

我有一个协议,它定义了具有类似属性编号的Sortable对象.

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
    }
}

“工人”协议

然后我有一个协议,可以使用这些Sortable类型做一些事情.但由于它具有自我要求,因此需要将其定义为具有关联类型的协议,并在结构中定义为通用属性

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),]

let handler = DataHandler(unsortedItems: array)

handler.sortedItems

这将根据我在处理程序中创建的分拣机类型以正确的顺序打印出项目数组

问题

我现在要做的是为这个排序器结构找到一个属性声明,可以将任何Sorter类型放入其中,但到目前为止我尝试过的所有内容都失败了.

有没有办法做到这一点?

在结构中,我想…

let sorter: SomeTypeHere

然后在init设置它就像…

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)
    }
}

您的处理程序现在可以与应用于Sortable类型的类型擦除AnySorter一起使用.例如,您在问题中提供的两个简单分拣机:

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,3,1]

let dataHandlerAsc = DataHandler(unsortedItems: arr,sorter: AnySorter(AscendingSorter()))
print(dataHandlerAsc.sortedItems) // [1,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?

是的,您可以使用AnySorter类型在DataHandler中保留属性.例如,对于一个人为的例子,我们可以让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,3]

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

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

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...