T.RawValue在Swift中的可比性是一笔生意吗?

时间:2017-02-24 19:23:55

标签: swift generics comparable

使用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 { }

下紧接着出现的运算符

这些运算符出现,表示对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< 1}}具有可比性。然而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 失败了。

这是尝试#2:

RawValue

同样,我们的Comparable类型为Comparable,但没有欢乐。

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

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

有趣。在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是一个协议,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_newtype Clang属性来定义与Swift桥接的类型的比较操作(有关此属性的更多信息,请参阅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))

(虽然这周围似乎有一些粗糙的边缘,例如试图直接使用它们会产生'模糊地使用'编译错误)

但是,对于“纯Swift”代码,您发现的重载应该没有任何意义。符合RawRepresentable Comparable RawValue s的Swift类型不会自动获得<重载或Comparable一致性 - 您必须自己实现。