Swift 5:在实现Equatable with protocol的结构上实现通用数组操作

Swift 5:在实现Equatable with protocol的结构上实现通用数组操作,swift,swiftui,Swift,Swiftui,我的应用程序中有两个符合协议的简单结构,以支持我需要在这两种类型上应用的一些通用操作: import UIKit protocol Track { var url: URL { get set } } struct TrackFromMediaFile: Track { var url: URL } struct TrackFromAsset: Track { var url: URL } 现在我有了这些结构的列表: var tracks = [Track]()

我的应用程序中有两个符合协议的简单结构,以支持我需要在这两种类型上应用的一些通用操作:

import UIKit

protocol Track {
    var url: URL { get set }
}

struct TrackFromMediaFile: Track {
    var url: URL
}

struct TrackFromAsset: Track {
    var url: URL
}

现在我有了这些结构的列表:

var tracks = [Track]()
tracks.append(TrackFromMediaFile(url: URL(string: "http://www.remotefile")!))
tracks.append(TrackFromAsset(url: URL(string: "local://localfile")!))
我需要在此曲目列表中查找特定曲目的索引:

// throws: 
// Value of protocol type 'Track' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols
var track = tracks[0]
tracks.firstIndex(of: track)
我试着遵循来自的方法,但没有效果,我无法将这些方法应用到我的示例中


如何实现以通用方式处理曲目数组?

不太清楚您想要的是哪种类型的相等。如果要同时检查类型相等性和值相等性,可以这样做:

tracks.firstIndex(where: {
    type(of: $0) == type(of: track) && $0.url == track.url
})
tracks.firstIndex(where: { $0.url == track.url })
如果您只想验证
url
是否相等,可以这样做:

tracks.firstIndex(where: {
    type(of: $0) == type(of: track) && $0.url == track.url
})
tracks.firstIndex(where: { $0.url == track.url })
在Swift中,equalable表示一个值可以与相同类型的其他值进行比较。它不适用于不同类型的值。协议不是类型,它描述类型,所以跟踪本身不能是相等的

如果你打算经常这样做,那么表达“能够检查与协议其他成员的平等性”通常是很方便的。这是不平等的,但肯定是可以表达的。看起来是这样的:

protocol Track {
    var url: URL { get set }
    func isEqual(to: Track) -> Bool
}
对于已经可均衡的轨迹一致性类型,可以提供默认实现:

extension Track where Self: Equatable {
    func isEqual(to other: Track) -> Bool {
        guard let other = other as? Self else { return false }
        return self == other
    }
}
并将您的一致性类型标记为可平衡(swift将自动创建一致性):

这样,代码就更好了:

tracks.firstIndex(where: { $0.isEqual(to: track) })
如果你经常这样做,你当然可以做得更好一点:

extension Collection where Element == Track {
    func firstIndex(of track: Track) {
        firstIndex(where: { $0.isEqual(to: track) })
    }
}
这样,您就可以使用以下语法:

tracks.firstIndex(of: track)

出于好奇,您是否希望
TrackFromMediaFile
trackfromsete
彼此相等?(我假设它们有你没有在这里列出的属性,是吗?)如果是,你能描述一下你想如何比较它们是否相等吗?我会创建一个带有枚举的公共结构来区分它们。你走错了路。你不应该有一个协议的集合。顺便说一句,如果你真的想遵循这个路径(我不推荐)
let index=tracks.firstIndex(其中:{track.url==0.url})
看起来我的问题真的没什么意义(equalable不属于协议)-我只需要使用数组上的where操作符。谢谢!似乎我对协议有错误的理解(我刚开始学习Swift),所以我的问题没有太多意义。您的回答为我指明了正确的方向-我只需要使用一些数组助手方法,如where。