Swift 可选类型: 如何理解 .None == nil 的工作原理

7

我正在尝试理解它是如何工作的:

  1> func returnNone() -> String? { return .None }
  2> returnNone() == nil
$R0: Bool = true
  3> returnNone() == .None
$R1: Bool = true

为什么.None等于nil

在枚举定义中我没有看到任何相关内容:

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
    case None
    case Some(Wrapped)
    /// Construct a `nil` instance.
    public init()
    /// Construct a non-`nil` instance that stores `some`.
    public init(_ some: Wrapped)
    /// If `self == nil`, returns `nil`.  Otherwise, returns `f(self!)`.
    @warn_unused_result
    @rethrows public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
    /// Returns `nil` if `self` is nil, `f(self!)` otherwise.
    @warn_unused_result
    @rethrows public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
    /// Create an instance initialized with `nil`.
    public init(nilLiteral: ())
}
1个回答

16

枚举 Optional 符合 NilLiteralConvertible 协议,这意味着它可以用 "nil" 文字初始化。结果是 Optional<T>.None,其中类型占位符 T 必须从上下文中推断出来。

以一个例子为例,

let n = nil // type of expression is ambiguous without more context

代码无法编译,但是

let n : Int? = nil

执行后结果为Optional<Int>.None

一般情况下,如果底层类型不是Equatable,则无法比较可选项:

struct ABC { }

let a1 : ABC? = ABC()
let a2 : ABC? = ABC()

if a1 == a2 { } // binary operator '==' cannot be applied to two 'ABC?' operands

甚至这个也无法编译:

if a1 == Optional<ABC>.None { } // binary operator '==' cannot be applied to two 'ABC?' operands

但是这个可以编译通过:
if a1 == nil { } 

它使用运算符。
public func ==<T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool

在官方文档中未对_OptionalNilComparisonType进行说明。 在https://github.com/andelf/Defines-Swift/blob/master/Swift.swift中可以找到定义(由@rintaro和@Arsen发现,请参见评论):

struct _OptionalNilComparisonType : NilLiteralConvertible {
  init(nilLiteral: ())
}

这使得任何可选类型与 "nil" 进行比较成为可能,无论底层类型是否是 Equatable

简而言之,在 Optional 的上下文中,可以将 nil 视为 .None 的快捷方式,但具体类型必须从上下文中推断出来。有一个专用的 == 操作符用于与 "nil" 进行比较。


1
@Arsen:实际上有一个运算符public func ==<T>(lhs: _OptionalNilComparisonType, rhs: T?) -> Bool_OptionalNilComparisonType没有记录,但这似乎允许比较任何可选类型与“nil”,无论基础类型是否可比。 - Martin R
@MartinR 看起来像是一个答案。你能更新一下你自己的回答吗?我认为这对人们来说可能很有趣。谢谢 :) - Arsen
@rintaro:谢谢!我找不到定义。 - Martin R
struct _OptionalNilComparisonType : NilLiteralConvertible { init(nilLiteral: ()) } - Arsen
我刚刚发现了这个链接 https://github.com/andelf/Defines-Swift/blob/master/Swift.swift 它不是官方文档。 - Arsen
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接