如何在 Swift 中专门化泛型协议?

问题描述 投票:0回答:1

我有这样的代码:

public class Metal {}

public protocol Vehicle<M> {
    associatedtype M
    
    var material: [M] { get set }
}

public protocol Tracktor: Vehicle where M == Metal {}

public protocol MetalTracktor: Tracktor {
    var material: [Metal] { get set }
}

无法编译

var material: [Meta]
的第二个定义,错误:

无法使用协变类型“[Metal]”覆盖类型“[Self.M]”的可变属性“材料”

为什么?用

Tracktor
类型专门化
Metal
的正确方法是什么?

我认为

Tracktor
已经专门用于
Metal
类型,因此第一个和第二个定义最终是相同的,因此不应发生冲突。我错过了什么?


我知道第二个定义是多余的,但是Swift通常允许冗余定义。为什么在这种情况下不呢?

swift generics template-specialization
1个回答
0
投票

Tracktor
协议已经专业化
Vehicle
。你已经做到了。

您可以为

Tracktor
编写一个实现,并使用
[Metal]
作为
material
的类型。

public class MyTracktor: Tracktor {
    public var material: [Metal] = []
}

Swift 首先判断

MyTracktor
是否符合
Vehicle
。它推断关联类型
M
Metal
。这隐式创建了一个
typealias
声明:

typealias M = Metal

现在

MyTracktor
满足
Vehicle
的两个要求,因此符合它。
MyTracktor.M == Metal
也是如此,所以符合
Tracktor

不允许在

var material: [Metal] { get set }
中写入
MetalTracktor
,因为在
MetalTracktor
的上下文中,
M
Metal
是两种不同(尽管相关)的类型。
M
是在
Vehicle
中声明的关联类型,
Metal
是在全局范围内声明的类类型。

将此与上面的

MyTracktor
类进行比较。在
MyTracktor
中,
M
Metal
类型别名
-
M
Metal
是同一类型。另一方面,
where M == Metal
表示的是
Tracktor
的要求,而不是类型别名。

从技术上讲,Swift 可以设计得更智能,并允许您在

var material: [Metal] { get set }
中编写
MetalTracktor
,但这并不是很有用,因为您只需编写
var material: [M] { get set }
即可完成基本相同的操作。

© www.soinside.com 2019 - 2024. All rights reserved.