为什么我们需要一个泛型?协议还不够吗?

2023-11-29

我在网上找到了以下关于将泛型与协议一起使用的示例,但是我不明白为什么我们根本需要泛型,而我们所需要的只是使用协议。

我们定义一个协议:

protocol Healthy {
    mutating func setAlive(status: Bool)
    var health: Int { get }
}

然后是一个使用通用协议的函数

func check<T:Healthy>(inout object: T) {
    if (object.health <= 0) {
        object.setAlive(false)
    }
}

我已将代码更改如下,一切仍然正常。

func check( object: inout Healthy) {
    if (object.health <= 0) {
        object.setAlive(status: false)
    }
}

Or not?

我能想到在那里使用泛型的唯一原因是,如果它是一个具有关联类型的协议并且它不能用作实例。


他们表达不同的东西。和

func check(object: inout Healthy) {

The object参数可以是any Healthy符合实例。因此,您可以这样做:

protocol Healthy {}

struct Foo : Healthy {}
struct Bar : Healthy {}

func check(object: inout Healthy) {
    object = Bar()
}

var h: Healthy = Foo()
check(object: &h)
print(h) // Bar()

我们打电话check(object:)并通过了h(其中持有一个Foo实例)作为inout争论,但最终得到h拿着一个Bar实例。

您会注意到,这意味着我们不能简单地调用check(object:)与混凝土类型inout争论。以下内容无法编译:

var h = Foo()

// compiler error: Cannot pass immutable value as inout argument: 
// implicit conversion from 'Foo' to 'Healthy' requires a temporary
check(object: &h)

Because check(object:)可以分配一个随意的 Healthy符合实例object参数,它不能分配给Foo多变的。

然而,随着

func check<T : Healthy>(object: inout T) {

The object参数是单一的specific具体类型符合Healthy(并且这种类型在调用站点得到满足)。你不能只分配一个任意的Healthy符合它的实例,因为它可能与作为传递的变量类型不兼容inout争论。

因此,现在允许您使用具体类型来调用它inout争论。我们现在可以说:

protocol Healthy {
    var alive: Bool { get set }
}

struct Foo : Healthy {
    var alive: Bool
}
struct Bar : Healthy {
    var alive: Bool
}

func check<T : Healthy>(object: inout T) {

    object.alive = false

    // illegal
    // object = Bar()
}

var h = Foo(alive: true)
check(object: &h)

(note h可以输入为Foo)

因此,在大多数情况下,您可能希望使方法变得通用,而不是使用协议类型inout参数,因为您可能想要处理具体类型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我们需要一个泛型?协议还不够吗? 的相关文章

随机推荐