【发布时间】:2018-02-09 18:49:16
【问题描述】:
在一致性类型指定数组类型的协议中,如何指定泛型属性?
信息:假设我们要创建一个定义数组的协议 数组类型未知的属性。符合的类型 指定此数组的类型。这是一个可能的解决方案:
protocol Wallet {
associatedtype Value
var moneyStack: [Value] {get set}
}
struct BitcoinWallet: Wallet {
var moneyStack: [String]
}
struct EthereumWallet: Wallet {
var moneyStack: [Int]
}
这种方法的问题是我们无法访问moneyStack 属性:
let bitcoinWallet = BitcoinWallet(moneyStack: ["A","B"])
let etheureumWallet = EthereumWallet(moneyStack: [1,2])
let wallets: [Wallet] = [bitcoinWallet, etheureumWallet]
for wallet in wallets {
print(wallet.moneyStack) // not possible
}
我们可以尝试另一种方法,其中数组的类型是任意的:
protocol Wallet {
var moneyStack: [Any] {get set}
}
struct BitcoinWallet: Wallet {
var moneyStack: [Any]
}
struct EthereumWallet: Wallet {
var moneyStack: [Any]
}
这是一个可能的解决方案,但包含 [Any] 的数组也是 通用的。我无法指定类型。示例:
let bitcoinWallet = BitcoinWallet(moneyStack: ["A","B"])
let ethereumWallet = EthereumWallet(moneyStack: [1,2])
var wallets: [Wallet] = [bitcoinWallet, ethereumWallet]
for wallet in wallets {
print(wallet.moneyStack.count) // this works
print(wallet.moneyStack[0]) // this works
}
let badBitcoinWallet = BitcoinWallet(moneyStack: [12.4, 312312.123]) // BitcoinWallets aren't allowed to hold doubles!
wallets.append(badBitcoinWallet) // This shouldn't be allowed!
第一个解决方案就是我想要的。每个结构中都指定了类型,但 Swift 抱怨我不能使用泛型约束。我要解决的主要问题是我想要一个包含不同类型钱包的数组,这些钱包都有自己的不同类型的数组。
我认为协议会使这变得简单,但事实并非如此。我的架构做错了吗?我什至应该使用协议吗?也许子类化可以解决这个问题?
【问题讨论】:
-
我觉得这有点令人不安,但请参阅 Rob Napier 关于此主题的有趣讨论:dotconferences.com/2016/01/…。
-
我能谈谈你对它为什么不舒服的看法吗?我很想听听您的反馈@Rob,这样我就可以看到其他观点。谢谢你的链接!
-
在类型擦除模式中,所有协议方法的所有闭包(然后您必须为每个符合类型重复)感觉有点笨拙,对于一些莫名其妙的限制来说是一种笨拙的解决方法在语言中(具有 typealias 的协议不能用作类型,而没有的协议则可以)。当你发现自己在重复一些这样的无脑代码时,这是一些更深层次问题的代码异味。 Rob Napier 自己也提到了这些问题,有趣的是,他对通用问题解决者的解决方案最终使用了完全不同的模式,即组合。
-
非常感谢@Rob!我希望我可以对评论进行投票,但该选项对我来说是不可见的。你说的有道理,我确实必须改变架构。
标签: ios swift generics swift-protocols