【问题标题】:Why can't I call Optional methods on an optional-chained type?为什么我不能在可选链类型上调用可选方法?
【发布时间】:2021-07-15 17:12:24
【问题描述】:

考虑以下示例,其中foo 被明确定义为可选:

let foo: Int? = 10
let bar = foo.map { $0 * 2 }

这会按预期编译和工作。现在考虑一个使用可选链接的后续示例:

let foo: [Int]? = [0, 1, 2]
let bar = foo?.count.map { $0 * 2 }

编译失败并显示以下消息:

error: value of type 'Int' has no member 'map'

为什么编译器将foo?.count 视为Int 而不是Int??这违背了Swift Language Book

为了反映可以对 nil 值调用可选链接这一事实,可选链接调用的结果始终是可选值,即使您正在查询的属性、方法或下标返回非可选值也是如此。

【问题讨论】:

    标签: swift


    【解决方案1】:

    这是一个运算符优先级问题。您需要添加括号来更改顺序:

    let bar = (foo?.count).map { $0 * 2 }
    

    考虑像 String 而不是 Int 这样的 Collection 的情况:

    let foo: String? = "ABC"
    let bar = foo?.uppercased().map(\.isLowercase) // [false, false, false]
    

    在这种情况下,.map 适用于 String 而不是 Optional 是明智的。如果优先级相反,那么您在每一步都需要一个?.(或很多括号:D)

    【讨论】:

    • 这是不正确的考虑尝试:让 i = 20; i.map({$0 * 1});这个操作会在swift中导致错误不是因为任何可选的优先级,而是因为int不能执行map。
    • 本书所指的是结果,而不是使用可选项的解包,实际上,如果不先解包,可选项不能与任何类型调用一起使用。这与删除问号以调用可选类型的计数相同。这在swift中不起作用。
    • @SeaSpell Optional 是一个枚举,它有自己的方法。这个问题是关于 Optional 的 .map 方法(存在),而不是 Int。例如,[1].first.map { $0 * 2 } 是有效(且有用)的 Swift。请注意缺少任何?(并且? 将无效)。它的返回类型是Int?
    • Optional 周围有一些神奇的语法(特别是?. 和 Optional 提升),但 Optional 本身并不神奇。它只是一个完全标准的枚举,用 Swift 编写:github.com/apple/swift/blob/main/stdlib/public/core/… 请注意描述“您必须先解开 Optional 实例的值,然后才能在许多上下文中使用它。”这是真的。但不是所有上下文。
    • 好吧,我同意你的观点, optional 可以调用 map, optional 确实是一个枚举,它确实在 optional 类型上定义了方法映射。我对这个问题的理解是为什么编译器出错。 Foo 是 Int 的可选数组,count 是 Array 的 var:RandomAccessCollection、MutableCollection,不是可选的。当 if foo 为 nil 时,无法调用 count。如果不是 nil,则在 [Int] 上调用计数,而不是在可选上。
    【解决方案2】:

    如果可用,count 的类型将解包为 Int。 Int 不实现函数映射。可选链接在找到 nil 时会失败。编译器试图告诉你如果它没有失败,操作映射就不会发生。结果是 bar ,它确实是一个可选的,因为如果操作失败(因为某些东西解包为 nil),整个链必须返回 nil。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-28
      • 2020-02-03
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多