【问题标题】:Loop through Swift struct to get keys and values循环遍历 Swift 结构以获取键和值
【发布时间】:2018-01-27 12:54:59
【问题描述】:

我想循环遍历 mystruct 的每个键,并为每个属性打印其 keyvalue

struct mystruct {
  var a = "11215"
  var b = "21212"
  var c = "39932"
}

func loopthrough {
    for (key, value) in mystruct {
        print("key: \(key), value: \(value)") // Type mystruct.Type does not conform to protocol 'Sequence'
    }
}

但是使用上面的几行我总是得到这个错误消息:

Type mystruct.Type 不符合协议'Sequence'

如何避免收到此消息?

【问题讨论】:

标签: swift struct


【解决方案1】:

首先让我们使用 CamelCase 作为结构名称

struct MyStruct {
    var a = "11215"
    var b = "21212"
    var c = "39932"
}

接下来我们需要创建一个 MyStruct 类型的值

let elm = MyStruct()

现在我们可以基于elm 值构建Mirror 值。

let mirror = Mirror(reflecting: elm)

Mirror 值确实允许我们访问 elm 的所有属性,方法如下

for child in mirror.children  {
    print("key: \(child.label), value: \(child.value)")
}

结果:

键:可选(“a”),值:11215

键:可选(“b”),值:21212

键:可选(“c”),值:39932

【讨论】:

  • 错字:你的意思是骆驼案例
  • 如何更改值?
  • @SantiPérez 实际上,它是标题大小写。 Camel case 以小写字母开头。
【解决方案2】:

使用以下代码获取所有属性的数组

protocol PropertyLoopable
{
    func allProperties() throws -> [String]
}

extension PropertyLoopable {
    func allProperties() throws -> [String] {

        var result: [String] = []

        let mirror = Mirror(reflecting: self)

        // Optional check to make sure we're iterating over a struct or class
        guard let style = mirror.displayStyle, style == .struct || style == .class else {
            throw NSError()
        }

        for (property,_) in mirror.children {
            guard let property = property else {
                continue
            }
            result.append(property)
         //   result[property] = value
        }

        return result
    }
}

现在就

let allKeys = try  self.allProperties()

别忘了实现协议

希望对你有帮助

【讨论】:

    【解决方案3】:

    您可以使用运行时内省(在您的类型的实例上)结合值绑定模式匹配来提取属性名称和值;后者用于解开 Mirror 实例的可选 label 属性,用于表示特定实例的子结构。

    例如:

    struct MyStruct {
        let a = "11215"
        let b = "21212"
        let c = "39932"
    }
    
    // Runtime introspection on an _instance_ of MyStruct
    let m = MyStruct()
    for case let (label?, value) in Mirror(reflecting: m)
        .children.map({ ($0.label, $0.value) }) {
        print("label: \(label), value: \(value)")
    } /* label: a, value: 11215
         label: b, value: 21212
         label: c, value: 39932 */
    

    【讨论】:

      【解决方案4】:

      我希望它仍然可以帮助某人: 这是我的协议版本,用于更复杂的类/结构(对象中的对象中的对象;-)) 我确信有一个更优雅的功能解决方案,但这是一个快速而肮脏的解决方案,因为我只需要它作为临时日志。

      protocol PropertyLoopable {
      func allProperties() -> [String: Any]
      }
      
      
      extension PropertyLoopable {
      func allProperties() -> [String: Any] {
          
          var result: [String: Any] = [:]
          let mirror = Mirror(reflecting: self)
          
          // make sure we're iterating over a struct or class
          guard let style = mirror.displayStyle, style == .struct || style == .class else {
              print("ERROR: NOT A CLASS OR STRUCT")
              return result
          }
          
          for (property, value) in mirror.children {
              guard let property = property else {
                  continue
              }
              // It was a very complicated struct from a JSON with a 4 level deep structure. This is dirty dancing, remove unnecessary "for" loops for simpler structs/classes
              // if value from property is not directly a String, we need to keep iterating one level deeper
              if value is String {
                  result.updateValue(value, forKey: property)
              } else {
                  let mirror = Mirror(reflecting: value)
                  
                  for (property, value) in mirror.children {
                      guard let property = property else {
                          continue
                      }
                      //let's go for a second level
                      if value is String {
                          result.updateValue(value, forKey: property)
                      } else {
                          let mirror = Mirror(reflecting: value)
                          
                          for (property, value) in mirror.children {
                              guard let property = property else {
                                  continue
                              }
                              //3rd level
                              if value is String {
                                  result.updateValue(value, forKey: property)
                              } else {
                                  let mirror = Mirror(reflecting: value)
                                  
                                  for (property, value) in mirror.children {
                                      guard let property = property else {
                                          continue
                                      }
                                      result.updateValue(value, forKey: property)
                                  }
                              }
                          }
                      }
                  }
              }
          }
          return result
      }
      

      }

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-03
      • 2019-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      相关资源
      最近更新 更多