【问题标题】:Swift - Binary operator '===' cannot be applied to two protocols [duplicate]Swift - 二元运算符'==='不能应用于两个协议[重复]
【发布时间】:2016-04-06 18:27:06
【问题描述】:

我正在尝试使用参考比较 (===) 来比较两种协议类型。当我这样做时(Foo 是协议):

Binary operator '===' cannot be applied to two 'Foo' operands

我明白为什么== won't work without conforming to Equatable,但在这种情况下我使用===,这只是一个地址比较。

【问题讨论】:

  • 这些是类协议吗? === 仅适用于类类型,不适用于值类型(结构、枚举)。如果协议没有声明为类协议,它就不会工作,因为编译器无法知道你是在比较类而不是结构。
  • @Sulthan 好点。但是不是所有的协议最终都会被一个类所遵循吗?
  • 不,因为结构体也可以符合协议

标签: swift


【解决方案1】:

=== 比较器用于比较引用 - 因为结构是值类型,它们按值传递并且没有引用。 (本质上传递一个结构只是需要一个副本)

类通过引用传递 - 实例存储在内存中,因此您可以使用=== 比较器。

所以是的,您可以比较它们,但您需要确保协议仅限于类。

例如

//: Playground - noun: a place where people can play

protocol Foo: class {

}

class A: Foo {

}

class B: Foo {

}

let a: Foo = A()
let b: Foo = A()
let c: Foo = B()

a === a // true
a === b // false
a !== c // true
b === c // false
c === c // true

在哪里

struct B: Foo {

}

编译失败

【讨论】:

  • 你比较对实例 os 类的引用,而不是协议。
  • @user3441734 它们被强制转换为协议类型 - 你告诉编译器你所知道的关于变量的所有信息都是它符合 Foo。它不知道 a 或 b 属于实例 A。
  • “你是在告诉编译器,你所知道的关于变量的所有信息就是它符合 Foo”,这是真的!但你仍然有你的类或结构等类型的实例。检查符合协议的变量的 .dynamicType 并将其值分配给某个类或结构等。
  • 底层将根据类实例检查它——但这就是为什么我们要将它限制在类中,因为结构是值类型并且没有引用地址。我不太确定你想在这里得到什么!
  • 查看我的答案中的示例,我现在就把它放在那里
【解决方案2】:

使用 === 可以比较某些实例的两个引用,但无法实例化协议类型!

protocol P {}
class C: P{}
let c = C()
let p:P = C()
c.dynamicType // C.Type
p.dynamicType // C.Type

let p:P = P() // error !!!

你可以告诉编译器你的协议是类协议

protocol P: class {}
class C: P{}
struct S: P{} // error: non-class type 'S' cannot conform to class protocol 'P'

确保没有符合它的值类型

看最后一个例子

protocol P: class {}
class C: P{}
let c = C()
let p:P = c

p === c  // true !!
let p1:P = c

p === p1 // true !!!

=== 运算符在这里工作

let c1 = C()
let p2:P = c1

p2 === p1 // false !!

【讨论】:

  • 你说得对,但同时这并没有提供任何帮助。因为您仍然可以通过“向下转换”符合协议的类的实例来拥有协议实例。
  • @luk2302 您可以比较对类实例的引用,而不是协议类型的实例。即使有人不同意,这就是现实。您无法创建协议实例。
  • @luk2302 向下转换不会改变动态类型。向下转换可以帮助您使用类型,因为它是协议的一个实例(隐藏所有类或结构......特定实现),但您仍然有一个“原始”动态类型的实例
  • 好的,亲爱的反对者,请给我一个如何创建对协议的引用的示例。这应该是比较两个参考文献的第一步
  • 虽然我还没有对你投反对票,但我相信你之所以投反对票是因为你没有回答这个问题,你只是说协议没有实例,这不是问题所在跨度>
【解决方案3】:

让我们在声明中说明问题:

=== 运算符是为 AnyObject 声明的。

public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool

AnyObject 到底是什么? AnyObject 是所有类都自动遵循的协议。

在 Swift 中,不仅有类类型,还有值类型,例如结构体和枚举。它们都可以符合协议,但结构和枚举不符合AnyObject。由于您有 Java 背景,值类型的行为类似于 Java 中的原始类型——它们是按值传递(复制)的,您通常不会得到对它们的引用。

当你声明一个协议时,编译器不知道它是否会被类或结构所采用。

protocol X {}

struct A: X {}

let x1: X = A()
let x2: X = A()

// PROBLEM - we cannot compare two structs by ===
if x1 === x2 {
}

这意味着我们必须告诉编译器该协议只能被类采用:

protocol X: AnyObject {}

protocol X: class {}

然后

class A: X {}  // can be adopted only by classes

let x1: X = A()
let x2: X = A()

// NO problem
if x1 === x2 {
}

【讨论】:

  • 您不是使用协议定义进行比较,而是使用类定义进行比较 - 您需要强制转换或告诉编译器类型,而不是让它被推断出来。
  • @OliverAtkinson 你是对的。
  • === 运算符在 AnyObject 协议中定义。您仍然无法创建 AnyObject 的实例。试着去做,让我知道......
  • "当你声明一个协议时,编译器不知道它是被类还是结构所采用。"但是你可以。协议 P:类 {}
  • 您能否编辑此答案,以便在将协议 X 声明为类协议后,将 A() 设为类,这是唯一缺少的位
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 2017-08-14
相关资源
最近更新 更多