【问题标题】:type any? has no subscript members输入任何?没有下标成员
【发布时间】:2016-08-15 14:13:54
【问题描述】:

我想从个人资料字典中获取地址,但我收到错误“type any? has no subscript members”

var address:[[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]]
var profile:[String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address]
profile["Addresses"][0]     <-----------------type any? has no subscript members

如何修复它并获取地址?非常感谢。

【问题讨论】:

  • 尝试在不使用任何类型的情况下重写您的代码
  • 我相信你最好使用类或结构作为地址和配置文件。
  • 请不要使用这样的字典。

标签: arrays swift dictionary any anyobject


【解决方案1】:

当您使用"Addresses" 为配置文件下标时,您将获得一个Any 实例。您选择使用Any 来适应同一数组中的各种类型已导致发生类型擦除。您需要将结果转换回其真实类型[[String: Any]],以便它知道Any 实例代表Array。然后你就可以下标了:

func f() {
    let address: [[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]]
    let profile: [String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address]

    guard let addresses = profile["Addresses"] as? [[String: Any]] else {
        // Either profile["Addresses"] is nil, or it's not a [[String: Any]]
        // Handle error here
        return
    }

    print(addresses[0])
}

虽然这很笨拙,而且首先使用字典并不是一个非常合适的情况。

在这种情况下,您的字典具有一组固定的键,结构是更合适的选择。它们是强类型的,因此您不必从Any 上下转换,它们具有更好的性能,并且更易于使用。试试这个:

struct Address {
    let address: String
    let city: String
    let zip: Int
}

struct Profile {
    let name: String
    let age: Int
    let addresses: [Address]
}

let addresses = [
    Address(
        address: "someLocation"
        city: "ABC"
        zip: 123
    ),
    Address(
        address: "someLocation"
        city: "DEF"
        zip: 456
    ),
]

let profile = Profile(name: "Mir", age: 10, addresses: addresses)

print(profile.addresses[0]) //much cleaner/easier!

【讨论】:

  • 感谢您的教导。你的解释很精彩。这是在同一个数组中修复各种类型的另一种方法?
  • 咦,这是个问题吗?
  • 是的,它有另一种方法来修复同一个数组中的各种类型吗? (对不起,我的英语很差.. :(
  • 不是真的,因为这不是真正应该做的事情。更严格的是做到这一点的方法
【解决方案2】:

您应该重新考虑如何选择构建adressprofile;参见例如Alexander Momchliov's answer.


对于技术讨论,您可以提取您知道的profileAny 成员,其中包含包装在Any 数组中的[String: Any] 字典;通过顺序尝试将profile["Addresses"] 类型转换为[Any],然后逐个元素(尝试)转换为[String: Any]

if let adressDictsWrapped = profile["Addresses"] as? [Any] {
    let adressDicts = adressDictsWrapped.flatMap{ $0 as? [String: Any] }
    print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"]
    print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"]
}

或者,没有中间步骤...

if let adressDicts = profile["Addresses"] as? [[String: Any]] {
   print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"]
   print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"]
}

但这只是尝试类型转换的一个小教训(-> 不要这样做)。

【讨论】:

  • 在这种情况下您不需要平面图。你可以直接(有条件地)强制[[String: Any]]
  • @AlexanderMomchliov 是的,该版本包含在我的答案的第二个代码块中(但我在您发表评论前 2 分钟将其包含在内,所以当您开始发表评论时它可能不存在):第一个替代方案以与原始profileaddress 变量定义相同的嵌套Any 顺序逐步进行转换(额外明确解释:)
  • 啊,是的,可能就是这样。迭代铸造实际上并不是发生的中间步骤。向下铸造始终是恒定的时间。 Iirc,只有向上转换需要循环,并且仅在某些情况下
  • @AlexanderMomchliov 啊,你误解了我(可能代表我的措辞不清楚),我在原始profileaddress 属性的定义中提到了“Any 的嵌套性” :第一个块是严格明确解释性 w.r.t。重新转换为嵌套在 Any 中的类型。
  • 是的,我明白了。我是说在第一个示例中,您使用平面地图作为引擎盖下发生的中间步骤。向下铸造始终是恒定的时间。只有向上转型有时需要迭代(IIRC)
【解决方案3】:

如果您按照之前的建议重新考虑您的设计,我同意这一点。为了讨论起见,您可以执行以下操作来实现您的目标。

var address:[[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]]
var profile:[String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address]
if let allAddresses = profile["Addresses"] as? [[String:Any]] {
    print("This are all the address \(allAddresses[0])")
    }

【讨论】:

    猜你喜欢
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    相关资源
    最近更新 更多