Swift结构体类型递归值

11

在Swift中,结构体不能具有递归值类型。因此,下面的代码无法在Swift中编译。

struct A {
    let child: A
}

值类型不能递归,因为它会具有无限大小。但我想知道为什么以下代码可以编译?

struct A {
    let children: [A]
}

2
孩子可以是空数组。 - Shadow Of
1
数组是一个结构体,但它不直接保存其值。 - Sulthan
2
如果包含的引用是可选的,你会认为这会起作用。 - Mike Bedar
4个回答

12

数组并不直接保存它的值。数组本质上是一个结构体,它保存对包含项的外部内存块的引用。因此,所有的数组占用相同的内存空间,可以在结构体中使用它们而不会出现问题。

举个例子:

struct Value {
    var array: [Int] = [] 
}

var value = Value()
value.array = [0, 1, 2, 3]  // this won't increase the size of the struct!

如果数组的行为不同,您将无法动态更改其大小(例如追加元素)或使用其写时复制行为。本质上,数组和字典是包装在值类型中的类。
因此,您的代码可以编译,因为它实际上不是递归的。

10

我认为这与所需空间有关。

无限空间

要创建此类型的值,

struct A {
    let child: A
}

我们需要:

  • 当前结构体的空间
  • 子结构体的空间
  • 子结构体的子结构体的空间
  • ......

所以,我们需要无限空间

有限空间

另一方面,要创建此值:

struct A {
    let children: [A]
}
我们只需要:
  • A所需的空间
  • 一个空的Array所需的空间。

2

由于child[]可以为空,所以这个方法应该是可行的。以下代码可以正常编译:

struct Foo {
  let child: [Foo]
}

let foo = Foo(child: [Foo(child:[Foo(child:[]), Foo(child:[])])])

虽然我看不出它有任何实际用途——但我想知道是否有用。


你的回答已经有一段时间了,但我找到了它的实际用途。目前正在尝试使用一个货币结构体,其中包含另一种参考货币的价值。 - SpacyRicochet

1

如果你知道一个Node只会有一个父节点(如果是leaf),那么你可以使用枚举和indirect case来实现:

public enum Node<Value> {
    case root(value: Value)
    indirect case leaf(parent: Node, value: Value)
}

public extension Node {
    var value: Value {
        switch self {
        case .root(let value): return value
        case .leaf(_, let value): return value
        }
    }
}

如果您知道您的节点始终会有两个父节点,您可以调整枚举案例来适应这种情况,等等。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接