我在网上发现了以下关于将泛型与协议一起使用的示例,但是当我们只需要使用协议时,我不明白为什么我们需要泛型。
我们定义了一个协议:
protocol Healthy {
mutating func setAlive(status: Bool)
var health: Int { get }
}
然后是一个使用通用adotping协议的函数
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)
}
}
或不?
我可以想到在那里使用泛型的唯一原因,如果协议具有关联类型并且它不能用作实例。
答案 0 :(得分:1)
他们表达不同的东西。随着
func check(object: inout Healthy) {
object
参数可以是任何符合 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
1}}实例。
您会注意到这意味着我们不能简单地使用具体类型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)
因为check(object:)
可以将任意 Healthy
符合要求的实例分配给object
参数,该参数不能分配给Foo
变量。< / p>
然而,
func check<T : Healthy>(object: inout T) {
object
参数是符合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)
(注意h
可以输入为Foo
)
因此,在大多数情况下,您可能希望将该方法设为通用,而不是使用协议类型inout
参数,因为您可能希望处理具体类型。
答案 1 :(得分:0)
因为这是使用inout
(ugh)并且没有返回值意味着不需要泛型。
当我在这个例子中使用泛型时,如果方法签名是这样的......
func check<T:Healthy>(object: T) -> T {
}
这将确保传入的对象类型和返回的类型是相同的类型。
如果没有通用名称,您可以传入...
的实例struct A: Healthy {}
并返回...的实例
struct B: Healthy {}
嗯......也许inout
的情况仍然如此。您是否可以创建符合协议的另一个结构并将object
更改为新结构的实例?也许......以后必须检查一下。