如何从不符合规范的 class 调用协议函数?

How to call a protocol function from a non-conforming class?

我正在使用协议,当我尝试从不符合协议的 class 调用它时,我的应用程序崩溃了。

问题的游乐场代码:

import Cocoa

var str = "Hello, playground"

public protocol example {
    func artihmetic(x: Int, y: Int) -> Int
}

class A : example {
    func artihmetic(x: Int, y: Int) -> Int { return x + y }
}

class B : example {
    func artihmetic(x: Int, y: Int) -> Int { return x * y }
}

class C {

    public init() {}

    func callArithmetic() {
        let x = 2, y = 2
        let z = (self as! example).artihmetic(x: x, y: y)
        print(z)
    }
}

let instC = C()
instC.callArithmetic()

这段代码崩溃了,我得到了这个错误:

Could not cast value of type '__lldb_expr_1.C' (0x112cd91c0) to '__lldb_expr_1.example' (0x7fff993f57e8)

我想知道是否有任何替代方法,或者是否可以从不一致的 class 调用协议函数。

您的错误是认为 Swift 具有某种结构类型,即

Hey, these types are similar enough in their structure (the methods, properties, etc. that they have), I should be able to freely cast between them.

完全不是这样。 Swift 对除元组和函数类型之外的所有内容都有一个 "nominal type system"。两个结构可以具有完全相同的实现,但名称不同,并且它们仍然是不同的、不兼容的类型。

self as! example

当你这样做时,编译器会像,"umm ok let me try that. Let's see the the type of self...ok. self is of type C. Is C a subclass of another type that conforms to example? No. Ok let me trying something else. Does the C class itself ever adopt the example protocol? No.! That's bad. I can't succeed. Oh shoot, they're using ! with as...I have to crash"

C需要采用example协议。你在这样做吗?没有!

另一个更明确的例子是:

protocol Feeder {
    func nurse()
}

class Human {
    func eat() {
        print("eat")
    }
}

class Man: Human{

}

class Woman: Human, Feeder {
    func nurse() {
        print("nurse baby")
    }
}

let human1: Human = Man()
let human2: Human = Woman()

func isFeeder(human: Human) {
    if let feeder = human as? Feeder { // very similar to: `self as! example`
        print("human is feeder!")
    } else {
        print("human is not feeder!")
    }
}

isFeeder(human: human1) // human is not feeder!
isFeeder(human: human2) // human is feeder!