【问题标题】:Why use generics when you can just use types [duplicate]当您只能使用类型时为什么要使用泛型[重复]
【发布时间】:2017-07-30 05:24:41
【问题描述】:

假设我有一个协议:

protocol Amazing {
     func doAmazingStuff()
}

然后我有一个函数可以使用该类型来处理它:

func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }

这和做这样的事情有什么区别?

func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }

我的问题是,当我们可以输入这样的类型时,为什么还要费心使用泛型?

更新 所以我可以看到使用遗传学而不是:

func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }

但是,使用该函数真的有什么用吗,还是使用泛型总是更好?

【问题讨论】:

标签: swift


【解决方案1】:

这只是我能立即想到的好处之一。我敢肯定还有更多。

假设我们有两个类AB,它们都符合Amazing

如果我们将A() 传递给这个函数:

func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }

像这样:

let val = doMoreCoolThings(awesome: A())

我们确信val 的类型是A,编译器也知道这一点。这意味着我们可以使用val 访问A 的成员。

另一方面,如果我们将A() 传递给这个函数:

func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }

像这样:

let val = doMoreCoolThings(awesome: A())

val 的编译时类型是Amazing。编译器不知道Amazing 是什么类型。是A 还是B 还是别的什么?编译器不知道。您必须将结果转换为 A 才能访问其成员。

let a = val as! A

演员也不能保证成功。

如果你把这些强制转换放在任何地方,你的代码很快就会变得非常混乱。

【讨论】:

  • 是的,这是有道理的,你能看看我的更新吗?
  • @Harish 关于您的更新,我的意见是,当返回类型不一定与传入的参数相同时,或者您不希望客户端使用的情况下,您应该使用接口投射结果。否则使用泛型。
  • 但是如果返回类型与传入的参数不同,你不能这样做吗:'''func doMoreCoolThings(awesome: T) -> R'''
  • @Harish 是的,你可以这样做。我的意思是当返回类型由方法的实现决定时,而不是由调用者决定。
【解决方案2】:

您的问题包含一个错误的前提,即

func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }

相当于:

func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }

这根本不是真的。假设我有这些符合要求的类型可以使用:

struct AmazingApple: Amazing {
    func doAmazingStuff() { print("I'm an apple who talks!") }
}

struct AmazingBanana: Amazing {
    func doAmazingStuff() { print("I'm a banana who talks!") }
}

看看第一段代码让我做什么:

func doMoreCoolThings(awesome: Amazing) -> Amazing {
    return AmazingBanana()
}

let input = AmazingApple()
let result = doMoreCoolThings(awesome: input)
print("The input is of type \(type(of: input))")
print("The return is of type: \(type(of: result))")

参数类型和返回类型是不同的,尽管它们都是Amazing的子类型。

另一方面,看看当你尝试对泛型变体做同样的事情时会发生什么:

泛型用于表达类型之间的关系。

非通用代码表示: “让doMoreCoolThings(awesome:) 成为一个函数,它接受一个类型为Awesome 子类型的值,并返回一个类型为Awesome 子类型的值。”

通用代码表示: “让doMoreCoolThings(awesome:) 是一个函数,它接受一个类型是某个类型的子类型的某个值,称它为T,并返回一个该类型是T 子类型的值,其中T 本身是一个子类型Amazing。”

请注意,第二个引号表示参数和返回必须是同一类型的要求。仅仅让它们都是Amazing 的子类型是不够的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多