我从 C++ 转向 Swift。我在协议和结构方面遇到了这种情况(我正在使用随机数):
(1) 协议
RandomPr
指定有一些方法,例如 randFloat()
返回 0 到 1 之间的 Float。RandomS
的结构体 RandomPr
。FakeRandomS
,它实现了 RandomPr
,但具有其他方法,例如 loadFloat()
来加载 Float 数组,然后当我在 randFloat()
实例上调用 FakeRandomS
时,这些 Float 数组会被反刍。 (用于测试目的。)
现在我有一个函数
DoSomething(rng: inout RandomPr)
,我想将其与 RandomS
和 FakeRandomS
一起使用。该参数必须是输入输出,因为我需要更新 RNG(无论是真还是假)。使用 DoSomething
的实例调用 RandomS
没有问题。
但是如果我这样做
var fakeRng = FakeRandomS()
fakeRng.loadFloat([0.1, 0.2, 0.3])
DoSomething(rng: &fakeRng)
我收到错误“Inout 参数可以设置为“FakeRandomS”以外类型的值。建议的修复是将
fakeRng
定义为
var fakeRng: RandomPr = FakeRandomS()
但是现在尝试在
loadFloat
上调用 fakeRng
会失败,因为 RandomPr
没有方法 loadFloat
,并且编译器看不到 fakeRng
有方法。
我尝试制作另一个协议
FakeRandomPr
,其中包含FakeRandomS
具有的额外方法,并定义
var fakeRng: RandomPr & FakeRandomPr = FakeRandomS()
但是,令人沮丧的是,我现在再次收到“Inout argument can be set to a value with a type other not ...”错误。
我可以在 C++ 中毫无问题地执行与此相同的操作(一个纯抽象基类和两个子类,通过引用传递),并且我想传递的其中一个内容是否有额外的方法并不重要。我想将其转换为协议和结构。 Swift 解决方案是什么?
Swift 解决方案是什么?
您可能需要使用泛型:
func doSomething<RP: RandomPr>(rng: inout RP) {
//...
}
Swift 不仅仅是 C++ 的另一种语法,更好地以 Swifty 的方式思考。
好的 - 我不久前发布了这个。现在我回过头来,并获得了一些理解,感谢 Hamish 在 Why do we need a generic here? 中的回答?协议还不够吗?.
我没有意识到,使用以协议形式给出类型的 inout 参数,整个输入对象可以被替换为完全不同类型的对象(在 Hamish 的示例中, struct Foo 类型的对象被 struct Bar 类型的对象替换) )。如果我随后使用该对象,除了它满足协议之外,我无法假设它的任何内容。
迟来的感谢哈米什。