我正在尝试将条件Equatable
一致性添加到类型sayBox<T>
,如果T
是Equatable
。由于Swift.Void
不是Equatable
,Box<Void>
不是Equatable
。
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
}
我可以像下面这样定义一个新类型作为解决方案:
public struct Empty: Equatable {
}
然后用
Box<Empty>
而不是Box<Void>
这样就行了。但是,想知道是否有其他方法来引入一种新的类型。更新:
我试过了,但没用
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
编译期间出错:
FooBarBaz does not conform to protocol Equatable
enum FooBarBaz: Equatable {
case success(box: Box<Void>)
// case success(box: Box<Int>) compiles as expected.
}
请注意,我使用的是Swift 4.1。
最佳答案
编译期间出错:FooBarBaz
不符合协议Equatable
这一半的答案集中在解释为什么你自己尝试过的方法还不能奏效。
目前,有一个条件符合性的限制,将限制您使用这种特定的技术来实现您的目标。引用SE-0143: Conditional conformances,在Swift 4.1中实施:
多重符合性
Swift已经禁止试图使同一类型符合的程序
同一协议两次,例如:
…
对多重符合性的现有禁令扩展到有条件的
符合性,包括在
两种不同的方式。
…
部分overlapping conformances描述了
由多个符合引入的复杂性,以证明它们
排除在本提案之外。后续建议可能会引入
支持多个符合项,但也可能包括
相关特征,如正交于
条件符合性。
它不允许我们构造多个条件一致性,例如:
struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: redundant conformance of 'Box<T>' to protocol 'Equatable'
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
另一方面,如果我们看看你自己的例子:
struct Box<T> { }
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: type 'Void' does not conform to protocol 'Equatable'
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>())
Swift准确地识别出
Box<Void>
不是Equatable
:扩展名Box where T == Void
并不意味着Box<Void>
符合Equatable
,因为当Box
是Equatable
时,它不利用T
到Void
的条件一致性(它只在==
是T
的情况下提供Void
方法)。条件一致性表达了一个概念,即泛型类型将
仅当其类型参数满足时符合特定协议
某些要求。
作为补充说明,下面的示例产生预期结果:
struct Box<T> { }
extension Box: Equatable where T == () {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // Box<()> is Equatable
然而,特别是,将
Box
到Equatable
ifT == ()
的条件一致性替换为typedef
的条件一致性,即使编译器崩溃:struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // compiler crash
断言失败:(isactuallicanonicalornull()&&“形成cantype
超出了非规范类型!“),函数类型,
文件/users/buildnode/jenkins/workspace/oss-swift-4.1-package-osx/swift/include/swift/ast/type.h,
第393行。
…
编辑:显然是一个(现在解决的)错误:
SR-7101: Compiler crash when implementing a protocol for an enum using generics