没有通用约束的协议中的通用数组

时间:2018-02-09 18:49:16

标签: ios swift generics swift-protocols

如何在符合类型指定数组类型的协议中指定通用属性?

  

信息:假设我们想要创建一个定义数组的协议   数组类型未知的属性。符合类型   指定此数组的类型。这是一个可能的解决方案:

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抱怨我不能使用泛型约束。我想解决的主要问题是我想要一个包含不同类型钱包的数组,它们都有自己不同类型的数组。

我认为协议会让这很容易,但事实并非如此。我的架构有问题吗?我应该使用协议吗?也许子类化可以解决这个问题?

1 个答案:

答案 0 :(得分:1)

您无法在阵列中存储2个不同类型的对象( tsess = tf.Session() tsess.run(tf.global_variables_initializer()) _, grads_and_vars, loss = tsess.run([train_op ,grads, loss], {x: 1.0, z: 1}) assert not np.isnan(loss), 'Something wrong! loss is nan...' #Get the gradients for g, v in grads_and_vars: if g is not None: grad_hist_summary = tf.summary.histogram("{}/grad_histogram".format(v.name), g) sparsity_summary = tf.summary.scalar("{}/grad/sparsity".format(v.name), tf.nn.zero_fraction(g)) Wallet<String>是不同的类型)。

但你可以尝试这样的事情:

Wallet<Int>