首页 > 解决方案 > 为什么 Swift 推断元类型“Any.Type”而不是类型“Any”?

问题描述

func giveMeZero<T>() -> T? {
    print(T.self)
    return 0 as? T
}

当在没有足够类型上下文的情况下调用上述函数时,Swift 将返回类型推断为元类型“Any.Type”,我希望它推断出“Any”或者可能会提供歧义错误。

// Calling code without type context, which exhibits the said behaviour
// prints 'no', since it's trying to cast 0 to Any.Type

if giveMeZero() != nil {
    print("yes")
} else {
    print("no")
}

输出:

"Any.Type\n"
"no\n"

标签: iosswiftgenericstype-inference

解决方案


为什么T不是Any

这很简单。没有为and==定义运算符,因为is not 。不可能。Any?Any?AnyEquatableTAny

为什么T可以Any.Type

这也很简单。有这样一个内置的运算符与此签名完全匹配。

func == (t0: Any.Type?, t1: Any.Type?) -> Bool

为什么不模棱两可

这更微妙。你会认为这T可能是StringorIntFloat,对吧?毕竟,它们都是Equatable,并且对于所有Equatable类型,都为它们Optional定义了==!=。但是,似乎在全局范围内声明的运算符被认为比在 的条件扩展中声明的运算符“更好” Optional,因此运算符重载决策总是首先选择非扩展运算符。这是合理的——毕竟,添加扩展不应该导致旧代码中断。

例如,添加此代码会使您的代码产生“模棱两可”的错误:

struct Foo {}

func ==(lhs: Foo?, rhs: Foo?) -> Bool {
    true
}

func !=(lhs: Foo?, rhs: Foo?) -> Bool {
    false
}

新添加的!=运算符 forFoo?和内置的运算符 forAny.Type?被认为同样适合调用giveMeZero() != nil

但是,这不会:

struct Foo { }
extension Optional where Wrapped == Foo {
    static func ==(lhs: Foo?, rhs: Foo?) -> Bool {
        true
    }

    static func !=(lhs: Foo?, rhs: Foo?) -> Bool {
        false
    }
}

推荐阅读