为什么 `Mirror.child.label` 字段没有正确处理自引用 类?

Why is the `Mirror.child.label` field not handling self-referential classes properly?

我在 Swift 中使用反射将通用对象 (Any) 写入 Swift 中的字典;用于教育和生产目的。

该代码有效,但我的一项测试表明,对于自引用 classes,它无法正常工作。

访问与class类型相同的成员字段时,Mirror.child.label字段returns取值some作为字典键,在访问之前成员的变量。

一个很好的例子:

class Node{
  var next: Node!
  var val: Int = 0

init(_ val: Int){
self.val = val
}

}
  
 
let node = Node(4)
node.next = Node(5)
node.next.next = Node(6)


print("node.toDictionary: " , toDictionary(obj: node))

输出为:

node.toDictionary:  ["val": 4, "next": ["some": ["next": ["some": ["val": 6, "next": [:]]], "val": 5]]]

不用说了,预期的输出是:

["next": ["next": ["val": 6],"val": 5],"val": 4]

产生此错误的 toDictionary 的最小代码是:

func toDictionary(obj: Any) -> [String:Any] {
    var dict = [String:Any]()
    let otherObj = Mirror(reflecting: obj)
    for child in otherObj.children {
        if let key = child.label {
          
            if child.value is String || child.value is Character || child.value is Bool
                || child.value is Int  || child.value is Int8  || child.value is Int16  || child.value is Int32 || child.value is Int64
                || child.value is UInt  || child.value is UInt8  || child.value is UInt16  || child.value is UInt32 || child.value is UInt64
                || child.value is Float  || child.value is Float32 || child.value is Float64 || child.value is Double
            {
                dict[key] = child.value
            }
            else if child.value is [String] || child.value is [Character] || child.value is [Bool]
                || child.value is [Int]  || child.value is [Int8]  || child.value is [Int16]  || child.value is [Int32] || child.value is [Int64]
                || child.value is [UInt]  || child.value is [UInt8]  || child.value is [UInt16]  || child.value is [UInt32] || child.value is [UInt64]
                || child.value is [Float]  || child.value is [Float32] || child.value is [Float64] || child.value is [Double]{
                
                let array = child.value as! [Any]
                
                
                dict[key] = array
                
                
            }else if child.value is [Any]{
                 let array = child.value as! [Any]
                 var arr:[Any] = []
                for any in array{
                    arr.append(toDictionary(obj: any))
                }
                dict[key] = arr
            }
            else{
                dict[key] = toDictionary(obj: child.value)
            }
            
        }
    }
    return dict
}

为什么 Mirror.child.label 字段没有正确处理自引用 classes?

原因是 var: next: Node! 是一个隐式展开的可选值,在许多情况下它们被视为常规可选值,例如

所以node.next的值实际上是Optional<Node>.some(nextNode),这导致创建的字典中的["some": ...]

该效果与 属性 的自引用无关,如下例所示:

class Bar {
    let value = 1
}

class Foo {
    var bar: Bar! = Bar()
}

let foo = Foo()
print(toDictionary(obj: foo))
// ["bar": ["some": ["value": 1]]]