swift 相同 属性 名称可选时的协议一致性

swift protocol conformance when same property name is optional

当协议将 属性 声明为 optional 而具体类型将其声明为 non-optional 时,如何我让具体类型符合协议?

这是问题所在:

protocol Track {
    var trackNumber: Int? { get } // not all tracks have a track number
}

struct SpotifyTrack {
    let trackNumber: Int // all SpotifyTrack are guaranteed to have a track number
}

extension SpotifyTrack: Track {
    var trackNumber: Int? {
        return self.trackNumber // WARNING: All paths through this function will call itself
    }
}

我不想在 SpotifyTrack 中将 trackNumber 设为可选,因为我知道 SpotifyTracks 的价值将始终存在。有没有比重命名属性更优雅的解决方案?

你可以有第二个 属性 作为第一个的支持:

protocol Track {
    var trackNumber: Int? { get }
}
struct SpotifyTrack {
    var realTrackNumber: Int
}
extension SpotifyTrack: Track {
    var trackNumber: Int? { self.realTrackNumber }
}

但是,我感觉这就是您所说的 "renaming":您不想那样做。然而,协议的 "instructions" 是固定的:如果不声明明确类型为 Int?.

trackNumber,就不能采用 Track

Objective-C 有 @optional 协议成员,这意味着你可以让 Track 声明 trackNumber Int 但 @optional,然后你可以在没有 [=11] 的情况下采用 Track =] 完全。但是如果你想利用它,这不能是一个结构。

一种方法可能是您有一个基本轨道协议,然后有一个扩展基本协议的第二个协议。例如

protocol BaseTrackProtocol {
    var title:String
    var artist:String
}

protocol SpotifyTrackProtocol : BaseTrackProtocol {
    var trackNumber:Int
}

struct SoptifyTrack: SpotifyTrackProtocol {
    var title:String
    var artist:String
    var trackNumber:Int
}

其他类型的轨道可以遵循基本轨道协议的不同扩展

希望对您有所帮助:)

除了重命名符合类型的冲突 属性 之外,您的问题没有优雅的解决方案。

Swift 不允许一个类型上存在 2 个同名的属性,即使它们的类型不同。另一方面,Int?Int是完全不同的类型,所以你不能让trackNumber: Int满足trackNumber: Int?的协议要求。

唯一的解决方案(除了更改 protocolstruct 中的类型)是重命名 SpotifyTrack 中的非可选 属性 并使返回非可选的同名的可选计算 属性。

protocol Track {
    var trackNumber: Int? { get }
}
struct SpotifyTrack {
    private let _trackNumber: Int
}
extension SpotifyTrack: Track {
    var trackNumber: Int? { _trackNumber }
}