T.RawValue 在 Swift 中可比是原始交易吗?



使用 Xcode 8.2.1 和 Swift 3,如果我显示Error协议的协议定义,我会在生成的标头中看到以下内容:

public protocol Error { }
extension Error { }
// at line 1250:
public func <<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func ><T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func <=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func >=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool

我的问题是关于紧随extension Error { }下方出现的运算符:

这些运算符似乎表示,对于具有ComparableRawValue子类型的类型存在默认实现。

所以我在游乐场里写了一些代码,看看我是否可以使用这些运算符。 这是第一次尝试:

struct S<RawValue> {
let v: RawValue
}
let s = S<Int>(v: 0)
let t = S<Int>(v: 1)
s < t  // error: Binary operator '<' cannot be applied to two 'S<Int>' operands

在上面的S结构中,我们有一个RawValue子类型,当实例化如变量st所示时,IntRawValue是可比的。 然而,<失败了。

这是尝试#2:

enum E: RawRepresentable {
case value(Int)
init(rawValue: Int) {
self = .value(rawValue)
}
var rawValue: Int {
switch self {
case .value(let rawValue):
return rawValue
}
}
}
let e = E.init(rawValue: 0)
let f = E.init(rawValue: 1)
e < f // error: Binary operator '<' cannot be applied to two 'E' operands

同样,我们有一个RawValue类型,它是Comparable,但没有快乐。

所以我想我在这里错过了一些基本的东西。 Swift "Misc" 标头告诉我T where T.RawValue: Comparable存在Comparable方法,但是当我尝试比较这些类型的T时,它不起作用。

有什么想法吗?

有趣。在 Swift 3.1 中,这些重载在生成的标头中显示为:

public func <<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func ><T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func <=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func >=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable

这更有意义,因为没有约束T,就不知道它有RawValue。所以它看起来像是 Swift 3.1 之前生成的标头中的视觉错误。

_SwiftNewtypeWrapper是一个协议,根据其标头,它是:

/// An implementation detail used to implement support importing
/// (Objective-)C entities marked with the swift_newtype Clang
/// attribute.
public protocol _SwiftNewtypeWrapper : RawRepresentable { }

因此,您看到的重载用于定义桥接到 Swift 的类型(通过使用swift_newtypeClang 属性进行标记(有关此属性的详细信息,请参阅本文)的比较操作,其中它们的RawValueComparable

例如,以下内容:

#import <Foundation/Foundation.h>
typedef NSString* _Nonnull Foo __attribute__((swift_newtype(enum)));
static const Foo FooBar = @"bar";
static const Foo FooBaz = @"baz";
static const Foo FooQux = @"qux";

桥接到 Swift 作为:

public struct Foo : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
public init(rawValue: String)
public static let bar: Foo
public static let baz: Foo
public static let qux: Foo
}

并且您可以将各种比较运算符与Foo实例一起使用:

func lessThan<T : _SwiftNewtypeWrapper>(lhs: T, rhs: T) -> Bool where T.RawValue : Comparable {
return lhs < rhs
}
let b = Foo.bar
print(lessThan(lhs: b, rhs: b))

(尽管这似乎有一些粗糙的边缘,例如尝试直接使用它们会产生"模棱两可的使用"编译器错误)

但是,对于"纯 Swift"代码,您发现的重载应该无关紧要。符合RawRepresentableComparableRawValue的 swift 类型不会自动获得<重载或Comparable一致性 - 您必须自己实现。

最新更新