Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Swift中使用协议类型强制转换异常_Swift_Casting_Protocols - Fatal编程技术网

在Swift中使用协议类型强制转换异常

在Swift中使用协议类型强制转换异常,swift,casting,protocols,Swift,Casting,Protocols,在处理类及其子类的实例时,我遇到了一种似乎是强制转换异常的情况,这两种类型都是作为类所遵循的协议键入的 由于我不想用我的领域的细节来复杂化这个问题,我在下面给出了一个人工例子来说明这个看似问题的存在 protocol P { func canCast(_ p: P) -> Bool } extension P { func canCast(_ p: P) -> Bool { return p as? Self != nil } } clas

在处理类及其子类的实例时,我遇到了一种似乎是强制转换异常的情况,这两种类型都是作为类所遵循的协议键入的

由于我不想用我的领域的细节来复杂化这个问题,我在下面给出了一个人工例子来说明这个看似问题的存在

protocol P {
    func canCast(_ p: P) -> Bool
}

extension P {
    func canCast(_ p: P) -> Bool {
        return p as? Self != nil
    }
}

class X: P {}
class Y: X {}

let a: P = X()
let b: P = Y()
由于
Y
X
的一个子类,我们应该能够将
b
转换为
X
,但我们不应该将
a
转换为
Y

这很好,如下所示:

print(a as? Y != nil)   // prints false
print(b as? X != nil)   // prints true
但是,当我使用协议中声明的
.canCast()
方法时,两个强制转换似乎都成功了:

print(b.canCast(a))     // prints true
print(a.canCast(b))     // prints true
我错过什么了吗

return p as? Self != nil

return p as? P != nil

根据@meggar发布的答案,我做了更多的工作,发现在这种情况下,
Self
总是表示符合协议的类型,而不是它的任何子类,无论该方法是在符合协议的类的实例上调用还是在它的任何子类上调用

所以在这种情况下,

return p as? Self != nil 

return p as? X != nil
对于
X
的实例以及
X
的任何子类的实例,此强制转换将成功,这就是问题中提出的两种情况下返回
true
的原因

为了证明这一点,我在协议扩展的方法体中添加了一行,以打印
self
的类型以及
self
表示的类型。我还创建了一个新类
Z
,它是
Y
的子类

下面给出了完整的修改代码,这表明
Self
继续表示
X
,而不管该方法是在
X
Y
还是
Z
(在每种情况下都是
Self
的类型)的实例上调用的

protocol P {
    func canCast(_ p: P) -> Bool
}

extension P {
    func canCast(_ p: P) -> Bool {
        print("Type of self: \(type(of: self)), Self represents: \(Self.self)")
        return p as? Self != nil
    }
}

class X: P {}
class Y: X {}
class Z: Y {}

let a: P = X()
let b: P = Y()
let c: P = Z()

print(a.canCast(b))
// Type of self: X, Self represents: X
// true
print(b.canCast(a))
// Type of self: Y, Self represents: X
// true
print(c.canCast(a))
// Type of self: Z, Self represents: X
// true