如何跨属性名称冲突的结构实现Swift协议

如何跨属性名称冲突的结构实现Swift协议,swift,swift-protocols,Swift,Swift Protocols,我正试图编写一个协议,协调描述相同概念的两个不同结构,某种类型的停止。两者都有code、Description和Latitude和Longitude坐标,但对于一种类型,Description可以是nil,而对于另一种类型,坐标可能是nil 如何编写协调这两个结构的单一协议 这是我的协议: protocol Stop { var Code : String { get } var Description : String { get } var Latitude : Do

我正试图编写一个协议,协调描述相同概念的两个不同结构,某种类型的停止。两者都有
code
Description
Latitude
Longitude
坐标,但对于一种类型,
Description
可以是
nil
,而对于另一种类型,坐标可能是
nil

如何编写协调这两个结构的单一协议

这是我的协议:

protocol Stop {
    var Code : String { get }
    var Description : String { get }
    var Latitude : Double { get }
    var Longitude : Double { get }
}
以及两种类型的站点:

struct BusStop : Stop {  // Compiler error: doesn't implement Description
    var Code : String
    var Description : String?
    var Latitude : Double
    var Longitude : Double
    // Various other properties
}

struct TrainStop : Stop {  // Compiler error: doesn't implement Latitude or Longitude
    var Code : String
    var Description : String
    var Latitude : Double?
    var Longitude : Double?
    // Various other properties
}
在C#(我的母语)中,我将编写一个明确的接口实现,如(伪代码):


但是,我不知道Swift中有任何类似的功能。鉴于我无法更改
BusStop
TrainStop
的现有属性定义,我如何编写
Stop
协议,使其环绕两个结构并在可用时返回属性?

显式接口实现所需的功能是静态调度它们,正确的?如果您在
公共汽车站上使用
说明
,它将是可选字符串,但如果您在
公共汽车站上使用
说明
,它将是非可选字符串

在Swift中,扩展成员是静态调度的,因此您可以利用它来实现类似的功能:

extension Stop where Self == BusStop {
    // Since the type of "self" here is BusStop, "Description" refers to the one declared in BusStop
    // not this one here, so this won't cause infinite recursion
    var Description : String { return self.Description ?? "" }
}

extension Stop where Self == TrainStop {
    var Latitude: Double { return self.Latitude ?? 0 }
    var Longitude: Double { return self.Longitude ?? 0 }
}
这段代码表明这是可行的:

let busStop = BusStop(Code: "ABC", Description: "My Bus Stop", Latitude: 0, Longitude: 0)
print(type(of: busStop.Description)) // Optional<String>
let stop: Stop = busStop
print(type(of: stop.Description)) // String
让公交车站=公交车站(代码:“ABC”,描述:“我的公交车站”,纬度:0,经度:0)
打印(类型(of:bustop.Description))//可选
停止:停止=公共汽车停止
打印(类型(of:stop.Description))//字符串

然而,我仍然不认为这是一个好的Swift代码。直接将API从一种语言翻译成另一种语言通常是不好的。如果我是你,我会让
经度
纬度
描述
中的
停止
成为所有选项。

我同意@Sweeper,如果你发现需要在同一个保护伞下使用不同的数据布局,那么你的设计可能不是最好的。尽管如此,我想分享另一种可能的方法来解决你的问题

您可以将所有
Stop
属性放入另一个结构中,让
Stop
协议返回该结构,而不是将所有
Stop
属性放入一个协议中:

协议停止{
var stopData:stopData{get}
}
结构停止数据{
变量代码:字符串
var stopDescription:字符串
纬度:双
经度:双
}
然后,可以为两个结构添加以下符合性:

struct总线停止:停止{
变量代码:字符串
var BustopDescription:字符串?
纬度:双
经度:双
var stopData:stopData{
返回StopData(代码:code,
stopDescription:busStopDescription??“”,
纬度:纬度,
经度(经度)
}
}
结构列车停止:停止{
变量代码:字符串
var trainStopDescription:字符串
纬度:双倍?
两倍?
var stopData:stopData{
返回StopData(代码:code,
stopDescription:trainStopDescription,
纬度:纬度??0,
经度:经度±0)
}
}
这意味着您将在应用程序的其余部分循环
StopData
实例,而不是
Stop
协议


另外,我还更改了房产名称,使其更符合Swift命名指南。

上周我曾考虑过这一点,但最后我认为这不是一个好主意。因为每次属性调用都有不必要的分配!这可能会导致性能下降,特别是当协议有太多属性时。如果swift有嵌套的计算属性,这种方法会很好。@MojtabaHosseini结构创建和使用起来很便宜。还要注意“过早的优化是万恶之源”(Donand Knuth)。如果您认为某些代码会带来性能问题,请确保对其进行分析,以查看它是否确实会对性能产生影响。如果表示SwiftUI的
视图的结构会怎么样?这些是否足够便宜,可以毫无顾虑地进行分配和解除分配?但我对你很不满。我必须描述并看到自己的行为。@MojtabaHosseini结构是结构,不管它们代表什么。让我们不要偏离问题的范围。我的任务是合并两个类似应用程序的功能,因此设计并不理想,但我正在尽可能统一概念以减少重复代码。你确定扩展成员是静态调度的吗?你能提供一个参考吗?@MojtabaHosseini有,还有一个类似的例子也显示了同样的行为。虽然找不到官方来源,但Swift官方参考IMO总是非常缺乏。如果我在
Stop
中使用
Description
Latitude
、和
Longitude
选项,那么我会在将它们定义为非选项的结构上得到相同的编译器错误。显然,optional和non-optional不能在两个方向上隐式强制转换。@Extragorey我的意思是,您仍然应该对协议扩展使用相同的技巧,但要使三个协议属性成为可选的。我是说,拥有一个具有非可选属性的协议,但具有可选属性的一致性类没有多大意义。如果可以的话,我会给它另一个+1。非常方便。
let busStop = BusStop(Code: "ABC", Description: "My Bus Stop", Latitude: 0, Longitude: 0)
print(type(of: busStop.Description)) // Optional<String>
let stop: Stop = busStop
print(type(of: stop.Description)) // String