T.RawValue 可比 Swift 是不公平的交易?

T.RawValue Comparable in Swift is a raw deal?

使用 Xcode 8.2.1 和 Swift 3,如果我显示 Error 协议的协议定义,我会在生成的 header 中看到:

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 { } 下立即出现的运算符:

这些运算符 似乎 表示存在 RawValue 子类型 Comparable.

的类型的默认实现

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

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 所示 Int RawValue 具有可比性。然而 < 失败了。

这是尝试 #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" header 告诉我 T where T.RawValue: Comparable 存在 Comparable 方法,但是当我尝试比较这些类型的 T 时,它并不存在没用。

有什么想法吗?

有意思。在 Swift 3.1 中,这些重载在生成的 header 中显示为:

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。所以它看起来像是 pre-Swift 3.1 生成的视觉错误 header.

_SwiftNewtypeWrapper是一个协议,其中according to its header是:

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

因此,您看到的重载用于定义桥接到 Swift 的类型的比较操作,方法是使用 swift_newtype Clang 属性进行标记(有关此属性的更多信息,请参阅this article),其中他们的 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))

(虽然这似乎有一些粗糙的边缘,例如尝试直接使用它们会产生 'ambiguous use of' 编译器错误)

但是,对于 'pure Swift' 代码,您发现的重载应该没有任何相关性。 Swift 符合 RawRepresentableComparable RawValue 的类型不会自动获得 < 重载或 Comparable 一致性——你必须实现它你自己。