这很难说出来,但我创造了一个最小的例子。
如果你更喜欢...... https://gist.github.com/anonymous/67d83fb2f286cf84539b58be96a971d3
,这是一个要点“数据项”协议
我有一个协议,用Sortable
属性定义number
个对象。
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),
BasicSortable(number: 3),
]
let handler = DataHandler(unsortedItems: array)
handler.sortedItems
根据我在Handler中创建的分拣机类型,以正确的顺序打印出项目数组
问题
我现在要做的是找到这个sorter
结构的属性声明,它可以将任何Sorter类型放入其中,但到目前为止我尝试过的所有内容都失败了。
有办法做到这一点吗?
在结构中我想要......
let sorter: SomeTypeHere
然后在init中设置它就像......
sorter = AscendingSorter()
但我尝试这样做没有任何组合起作用。
由于
答案 0 :(得分:4)
您可以使用类型擦除来实现自己的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]
类型一起使用。例如,您在问题中提供的两个简单分拣机:
AnySorter<T>
编辑附加内容以回答您的评论:
是否可以获取输入参数并将其存储在属性中? 我会使用
DataHandler
作为属性的类型吗?
是的,您可以在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]
实例对存储的项目列表进行排序(当然,实际上我们并不想要对每个调用进行重新排序,但仅限于此示例!):
cmd := exec.Command("ls","lh")
outfile, err := os.Create("./out.txt")
if err != nil {
panic(err)
}
defer outfile.Close()
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
writer := bufio.NewWriter(outfile)
defer writer.Flush()
err = cmd.Start()
if err != nil {
panic(err)
}
go io.Copy(writer, stdoutPipe)
cmd.Wait()
答案 1 :(得分:3)
如果符合Sorter
的给定类型的实例可以处理符合Sortable
的任何同质元素数组(如果它仅限于单个具体类型,则{ {3}}让你了解了 - 然后Sorter
首先不需要associatedtype
。您可以简单地将sort(items:)
方法设为通用,这样您就可以使用Sorter
作为类型。
另外,如果您的sort(items:)
方法没有使用任何实例状态(它不在您的示例代码中),那么您可以将其设为static
- 并简单地绕过分拣机的类型,而不是实例。
例如,您的Sortable
协议和BasicSortable
实施:
protocol Sortable : Comparable {
var number : Int { get }
// note that you don't need to re-define the < and == operator requirements,
// as they're already defined by Comparable and Equatable
}
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
}
}
您的Sorter
协议以及不同的分拣机实施:
protocol Sorter {
// A sort function that can take any homogenous array of a given
// Sortable element (meaning that an instance of a type that conforms to
// Sorter isn't restricted to a single concrete type of Sortable).
// As the function doesn't rely on any instance state, it's static.
static func sort<T:Sortable>(items: [T]) -> [T]
}
// Two different sorters
enum AscendingSorter : Sorter {
static func sort<T:Sortable>(items: [T]) -> [T] {
return items.sorted(by: <)
}
}
enum DescendingSorter : Sorter {
static func sort<T:Sortable>(items: [T]) -> [T] {
return items.sorted(by: >)
}
}
最后,您的DataHandler
使用了一个示例:
struct DataHandler<T: Sortable> {
let items: [T]
private(set) var sortedItems: [T]
var sorter : Sorter.Type { // simply hold a given type of sorter
willSet {
if sorter != newValue {
// re-sort items upon (different) sorter being set
sortedItems = newValue.sort(items: items)
}
}
}
init(unsortedItems: [T], sorter: Sorter.Type) {
items = unsortedItems
self.sorter = sorter
sortedItems = sorter.sort(items: unsortedItems)
}
}
let items = [BasicSortable(number: 2), BasicSortable(number: 4), BasicSortable(number: 6),
BasicSortable(number: 1), BasicSortable(number: 4)]
var handler = DataHandler(unsortedItems: items, sorter: AscendingSorter.self)
print(handler.sortedItems)
// [BasicSortable(number: 1), BasicSortable(number: 2), BasicSortable(number: 4),
// BasicSortable(number: 4), BasicSortable(number: 6)]
handler.sorter = DescendingSorter.self
print(handler.sortedItems)
// [BasicSortable(number: 6), BasicSortable(number: 4), BasicSortable(number: 4),
// BasicSortable(number: 2), BasicSortable(number: 1)]
答案 2 :(得分:0)
您的sorter
属性不能被声明为常规Sorter
,因为正如您所指出的那样,它有Self
要求,但我相信您可以这样做您向DataHandler
添加第二个类型参数,使其看起来像
struct DataHandler<T: Sortable, S: Sorter> {
let items: [T]
let sortedItems: [T]
let sorter: S
init(unsortedItems: [T], sorter: S) {
items = unsortedItems
self.sorter = sorter
sortedItems = self.sorter.sort(items: unsortedItems)
}
}