Swift 4,Generics为什么我需要在这里强制转换为T?

时间:2018-09-27 20:06:03

标签: swift generics

在Swift 4中运行此代码时,编译器将引发以下错误:

"Cannot convert return expression of type 'Comment?' to return type '_?', when running this code in a playground:
import UIKit

class Comment {}
class Other {}

func itemForSelectedTabIndex<T>(index: Int, type: T.Type) -> T? {
    return (type is Comment.Type) ? getComment() : getOther() 
}


func getComment() -> Comment {
    return Comment()
}

func getOther() -> Other {
    return Other()
}

let thing = itemForSelectedTabIndex(index: 0, type: Other.self)

为了使它起作用,我需要将返回值强制转换为通用值,如下所示:

return (type is Comment.Type) ? getComment() as! T : getOther() as! T

有人可以解释其背后的逻辑吗?

如果期望的返回值是'Generic',并且基本上返回的类型无关紧要,为什么编译器会抱怨呢?不铸就不行吗?

1 个答案:

答案 0 :(得分:1)

泛型不是一些可以随时具有任何价值的神奇通配符。

当您致电itemForSelectedTabIndex(index: 0, type: Comment.self)时,T被推断为Comment。同样,对于Other

T推断为Comment时,T的相同值在使用的所有位置都是一致的。因此,返回值必须为Comment类型(或子类型)。

另一个与您的表情(type is Comment.Type) ? getComment() : getOther()在一起。有2种情况,但都不有效:

  1. typeComment.TypegetComment()返回Comment,该类型与T的值Comment兼容。但是,条件运算符的两个操作数没有共同的超类型。那是无效的。
  2. type not Comment.TypegetOther()返回一个Other,它可能兼容也可能不兼容与T。我们对T所了解的只是它不是评论。这并不意味着它一定是Other。它可以是任何其他类型,例如Int。因此,此返回表达式失败。

您需要的是您希望返回的两种类型的通用超类型。协议很可能是正确的选择(而不是共享的超类):

protocol TabItem {}

class Comment {}
class Other {}

func itemForSelectedTabIndex<T: TabItem>(index: Int, type: T.Type) -> TabItem {
    return getCommentOrOtherOrSomethingElse()
}