代码之家  ›  专栏  ›  技术社区  ›  drekka

Swift:返回一个可选的泛型函数不会做什么?

  •  0
  • drekka  · 技术社区  · 3 年前

    我设计了这个代码来尽可能简单地说明我的问题。如果我有这样一个通用函数:

    func get<T>() -> T? {
        // For example purposes I'm hard coding the result.
        return 5 as? T
    }
    
    if let x = get() as? Int { /* Won't compile: Generic parameter 'T' could not be inferred */ }
    if let x = get() as Int? { /* true */ }
    if let x: Int? = get() { /* true */ }
    

    现在我的问题是,为什么第一个不编译?

    我可以使用其他表格,但那是我想使用的表格,所以我想知道为什么我不能。

    0 回复  |  直到 3 年前
        1
  •  4
  •   Sweeper    3 年前

    这可能是因为 difference between as and as? 。关键的区别在于,如果使用 ,编译器必须能够在编译时告知转换有效/将成功。

    因此,实际类型是有限制的 get 可以返回。最终,类型检查器决定 T Int . Keep in mind that the Swift typechecker works on a constraint system.

    另一方面,如果您使用 ,LHS表达式可以是任何类型,并且不存在编译时检查。将在运行时检查强制转换,如果失败,表达式的计算结果为nil。因此 并不限制其LHS表达的类型。

    我在Swift编译器的源代码中找到了相关的代码部分,所以如果你愿意,你可以自己进一步探索。正如你所看到的,在 visitCoerceExpr ( foo as T ),它是这样做的:

      // Add a conversion constraint for the direct conversion between
      // types.
      CS.addExplicitConversionConstraint(fromType, toType, RememberChoice,
                                         locator);
    

    它在中没有做到 visitConditionalCheckedCastExpr ( foo as? T ).

    请注意,如果您不使用 T 里面的任何其他地方 收到 ,你可以直接回来 Any ,并让调用者进行强制转换。这将允许您使用 as? Int 语法。

    func get() -> Any {
        // ...
        return 5
    }
    
    if let x = get() as? Int { /* ... */ }
    
        2
  •  2
  •   matt    3 年前

    扫路者的回答很好(和往常一样);我只是想换一种方式,也许更简单地表达同样的观点。这只是两者之间的区别 告诉 询问 .

    编译器需要 告诉 T是什么。这就是解析/专门化泛型的意义所在。当你说 as Int? :Int? ,那正是你正在做的。你是 告诉 这个东西是的编译器 Int? (因此编译器可以推断 T Int ).

    但是当你说 as? ,你根本没有这么做。这与Optionals或任何其他类型无关。你只是 询问 (运行时)这是什么类型。您不是 告诉 编译器(或任何人)任何东西。所以编译器不知道,你也不能编译。