Swift:为什么在这种情况下 CustomStringConvertible 描述 运行 太多次?

Swift: Why the CustomStringConvertible description is run too many times in this case?

我在 Xcode Playground 中尝试这段代码,发现 description getter 方法被调用了太多次。

代码在这里:https://gist.github.com/T-Pham/4b72d17851162a32b2fc534f0618135d

首先用 print 行,代码是 运行 3176 次。

然后把第一个print注释掉,代码是运行3164次

这意味着第一个 print 必须 运行 代码 12 次。 然而,

反而是148次

让你头疼的是游乐场

Playground 正在计算它自己对具有 CustomStringConvertibe 协议的变量的调用(可能是为了在右侧面板上提供信息)。

如果你只是调用 mirror(tree) 而根本不打印,你可以看到这种情况。

如果您使用自己的计数器来计算实际调用次数,则会得出截然不同的结果:

 var descCount = 0
 extension Node: CustomStringConvertible {
     var description: String 
     {
         descCount += 1
         return "id: \(id)\nleft: \(left)\nright: \(right)"
     }
 }

 descCount = 0
 print(tree)
 descCount   // 12

 descCount = 0
 print(mirror(tree))
 descCount   // 12 

顺便说一句,我在理解 mirror() 函数时遇到了一些困难,我认为递归的函数可能更容易理解。如何向 Node 添加 mirror() 函数:

 func mirror() -> Node
 {
    let result = Node()
    result.id      = id
    result.left    = right?.mirror()
    result.right   = left?.mirror()
    return result
 }

 print(tree.mirror())

[编辑] 这是一个结构更清晰的非递归镜像函数(与您的逻辑相同):

 func mirror2(tree:Node) -> Node
 {
    // will return top of mirrored tree
    let newTree = Node()

    // node pair used for traversal and duplication
    var original:Node! = tree
    var mirrored:Node! = newTree

    // traversal of tree structure left side first
    // (uses mirrored tree to keep track of traversed nodes)
    while original != nil
    {
       // carry node identifier (and contents eventually)
       mirrored.id = original.id 

       // downwards, mirror left side first (if not already done)
       if (original.left == nil) != (mirrored.right == nil)
       {
          original       = original.left
          mirrored.right = Node()
          mirrored       = mirrored.right 
          continue     
       }

       // downwards, mirror right side second (if not already done)
       if (original.right == nil) != (mirrored.left == nil)
       {
          original      = original.right
          mirrored.left = Node()
          mirrored      = mirrored.left
          continue
       }

       // upwards from leaves and completed branches
       original = original.parent
       mirrored = mirrored.parent
    }
    return newTree
 }

还有一些用于树木描述的视觉糖果:

 extension Node: CustomStringConvertible 
 {
     var indent:String 
     { return "  " + (parent?.indent ?? "") }
     var description: String 
     {
         return "\(id)\n"
              + ( left  != nil ? "\(indent)L:\(left!)" : "" )
              + ( right != nil ? "\(indent)R:\(right!)" : "" )
     }
 }

更容易比较结果:

 print(tree)

 // 0
 //   L:1
 //     L:3
 //       L:7
 //       R:8
 //     R:4
 //       L:9
 //       R:10
 //   R:2
 //     R:6
 //       L:13
 //       R:14
 //

 print(mirror2(tree))

 //  0
 //    L:2
 //      L:6
 //        L:14
 //        R:13
 //    R:1
 //      L:4
 //        L:10
 //        R:9
 //      R:3
 //        L:8
 //        R:7