我有一系列不同的结构,都实现了Equatable
协议,并试图将其传递给需要collection的函数where T.Iterator.Element: Equatable
。我知道如何使用类来解决此问题,只需创建一个class Vehicle: Identifiable, Equatable
,然后制作Car
并Tractor
实现Vehicle
。但是我想知道使用结构和协议是否可行?
这是我想要做的一个人为的例子
//: Playground - noun: a place where people can play
protocol Identifiable {
var ID: String { get set }
init(ID: String)
init()
}
extension Identifiable {
init(ID: String) {
self.init()
self.ID = ID
}
}
typealias Vehicle = Identifiable & Equatable
struct Car: Vehicle {
var ID: String
init() {
ID = ""
}
public static func ==(lhs: Car, rhs: Car) -> Bool {
return lhs.ID == rhs.ID
}
}
struct Tractor: Vehicle {
var ID: String
init() {
ID = ""
}
public static func ==(lhs: Tractor, rhs: Tractor) -> Bool {
return lhs.ID == rhs.ID
}
}
class Operator {
func operationOnCollectionOfEquatables<T: Collection>(array: T) where T.Iterator.Element: Equatable {
}
}
var array = [Vehicle]() //Protocol 'Equatable' can only be used as a generic constraint because Self or associated type requirements
array.append(Car(ID:"VW"))
array.append(Car(ID:"Porsche"))
array.append(Tractor(ID:"John Deere"))
array.append(Tractor(ID:"Steyr"))
var op = Operator()
op.operationOnCollectionOfEquatables(array: array) //Generic parameter 'T' could not be inferred
正如错误所指出的那样,问题是,您不能将具有“自我”或相关类型要求的协议用作实际类型,因为您会丢失有关这些要求的类型信息。在这种情况下,您将丢失==
实现参数的类型信息,因为Equatable
它们必须与一致类型(即Self
)具有相同的类型。
解决方案几乎总是建立一个类型的橡皮擦。在期望类型相等的情况下,如果它们的id
属性相等,则可以简单地id
将其存储起来并在==
实现中进行比较。
struct AnyVehicle : Equatable {
static func ==(lhs: AnyVehicle, rhs: AnyVehicle) -> Bool {
return lhs.id == rhs.id
}
let id : String
init<T : Vehicle>(_ base: T) {
id = base.id
}
}
(请注意,为了符合Swift命名约定,我将您的ID
属性重id
命名为)
但是,更通用的解决方案是在类型橡皮擦中存储一个函数,该函数可以在类型转换之后Vehicle
根据 其
==
实现比较两个任意符合的实例,以确保它们与创建类型橡皮擦的具体类型相同。 。
struct AnyVehicle : Equatable {
static func ==(lhs: AnyVehicle, rhs: AnyVehicle) -> Bool {
// forward to both lhs's and rhs's _isEqual in order to determine equality.
// the reason that both must be called is to preserve symmetry for when a
// superclass is being compared with a subclass.
// if you know you're always working with value types, you can omit one of them.
return lhs._isEqual(rhs) || rhs._isEqual(lhs)
}
let base: Identifiable
private let _isEqual: (_ to: AnyVehicle) -> Bool
init<T : Vehicle>(_ base: T) {
self.base = base
_isEqual = {
// attempt to cast the passed instance to the concrete type that
// AnyVehicle was initialised with, returning the result of that
// type's == implementation, or false otherwise.
if let other = $0.base as? T {
return base == other
} else {
return false
}
}
}
}
print(AnyVehicle(Car(id: "foo")) == AnyVehicle(Tractor(id: "foo"))) // false
print(AnyVehicle(Car(id: "foo")) == AnyVehicle(Car(id: "bar"))) // false
print(AnyVehicle(Car(id: "foo")) == AnyVehicle(Car(id: "foo"))) // true
var array = [AnyVehicle]()
array.append(AnyVehicle(Car(id: "VW")))
array.append(AnyVehicle(Car(id: "Porsche")))
array.append(AnyVehicle(Tractor(id: "John Deere")))
array.append(AnyVehicle(Tractor(id: "Steyr")))
var op = Operator()
// compiles fine as AnyVehicle conforms to Equatable.
op.operationOnCollectionOfEquatables(array: array)
大多数我们在其他类型上使用的操作符,例如数学运算符( +, %等)以及比较运算符(==,>等),都不适用于结构体。事实上,可以为这种新类型定义这些操作符的含义,不过在这本书中我们不会这么做。 另一方面,赋值运算符确实适用于结构。它可以用在两种方式上:初始化结构的实例变量或把实例变量从一个结构复制到另一个结构。一个初始化结构看起来像这样: Point blank = { 3.0, 4.0 }; 大
冯·诺依曼体系结构 计算机处理的数据和指令一律用二进制数表示 顺序执行程序 计算机运行过程中,把要执行的程序和处理的数据首先存入主存储器(内存),计算机执行程序时,将自动地并按顺序从主存储器中取出指令一条一条地执行,这一概念称作顺序执行程序。 计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。 数据的机内表示 二进制表示 机器数 由于计算机中符号和数字一样,都必须用二进制数串来表
问题内容: 说我有以下实体: 我正在尝试建立一个标准查询,该查询根据BaseEntity和两个子类中的属性返回BaseEntity的实例。因此,本质上,我正在寻找与该伪SQL相对应的条件查询: 我不想构建两个单独的查询,因为它们有很多重叠(即,大多数属性都在基类中)。但是,如果我将BaseEntity声明为根,我还没有想出一种在查询中引用子类属性的方法。是否可以建立这样的条件查询? 更新: 也许一
问题内容: 我有一个看起来像这样的结构: 如何实现扫描仪的接口属性来解析类型超出,或Redis的哈希值? 如何计算值并将其分配给authEnum?在我的代码示例中,永远不会调用。 问题答案: 在指针接收器上实现该方法。Redis批量字符串表示为[] byte,而不是字符串: 始终检查并处理错误。从返回的错误报告类型问题。 无需检查指向struct成员的nil指针。如果ScanStruct的参数为n
问题内容: 我有一个想要有效地进行JSON编码的结构: 该结构包含一个已知形式的元数据和一个未知形式的目录。目录列表在运行时填充,因此我并没有真正的控制权。为了提高Go的编组速度,我想在Meta结构上实现Marshaller接口。Marshaller界面如下所示: 请记住,元结构并不像这里所示的那么简单。我尝试过在Meta结构上实现Marshaler接口,但似乎当我再将JSON编组MyStruct
本文向大家介绍Java 数据结构链表操作实现代码,包括了Java 数据结构链表操作实现代码的使用技巧和注意事项,需要的朋友参考一下 链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面将逐一介绍。链表在数据结构中是基础,也是重要的知识点,这里讲下Java 中链表的实现, JAVA 链表操作:单链表和双链表 主要讲述几点: 一、链表的简介 二、链表实现原理