【问题标题】:Array of slices - GO切片数组 - GO
【发布时间】:2017-01-28 06:49:24
【问题描述】:

1)

对于下面的切片声明,

var a [][3]string

创建一个指向 3 个字符串数组的单个切片 (a),len(a) = 3 和 cap(a) =3,但不指向 cap(a) >= 3

a = make([][3]string, 5)

创建 5 个切片,其中每个切片(例如 a[0])指向 3 个字符串数组,len(a[0]) = 3 和 cap(a[0]) = 3


2)

对于切片声明,

var b [][3][6]string

创建一个切片 (b),它指向 3 个数组,每个数组包含 6 个字符串,其中 len(b) = 3 和 cap(b) =3

b = make([][3][6]string, 5)

创建 5 个切片,其中每个切片(例如 b[0])指向 3 个数组,每个数组包含 6 个字符串


在这两种情况下,在制作切片后,我说,创建 5 个切片,


考虑到语法,下面是我的两个问题,

a = make([][3]string, 5)

我的问题:

1)

是 5 个切片,每个切片(a[0])是 3 个字符串的数组吗?

或

它是单个切片(a)指向 5 个数组,每个数组包含 3 个字符串吗?

2)

我如何知道元素的类型?切片还是数组?

1) 在这种情况下,必须谨慎使用“数组”术语。

2) GO 不像 C 那样涉及隐式指针

【问题讨论】:

    标签: arrays go slice


    【解决方案1】:

    切片和数组是两种不同的类型:内存中的数组是相同类型值的连续序列。在 Go 中,类型具有固定大小。例如,在 C++ 和

    中存在完全相同的概念
    int x[5]; // C and C++
    x [5]int  // Go
    

    基本上是相同的(不是 100% 相同,因为 C 和 C++ 中的数组是“二等公民”并且在一些地方表现得很奇怪,Go 在这方面更加统一)。

    Go 中的切片是数组一部分的“视图”,它或多或少等价于 C++ 结构,其中包含指向第一个元素的指针、许多使用的元素(相对于第一个元素)和一个可用元素的数量(相对于第一个)

    // C++
    template<typename T>
    struct Slice {
        T *first;
        int size, capacity;
    };
    Slice<int> x{nullptr, 0, 0};
    
    // Go
    var x []int
    

    Make 特殊函数能够创建与新创建的数组关联的切片,给定大小和可选容量:

    // C++
    template<typename T>
    Slice<T> make(int size, int capacity=-1) {
        if (capacity == -1) capacity = size;
        return Slice<T>{new T[capacity], size, capacity};
    }
    
    // Go
    x := Make([]int, size, capacity)
    

    切片可以在 O(1) 中有效地传递(独立于大小/容量),您还可以在 O(1) 中获取切片的子切片...请注意,Go 是垃圾收集的,执行在 C++ 中同样需要一些额外的工作(例如,还要保留指向原始数组对象的指针及其在切片中的大小)。

    您当然可以有切片数组、切片切片、数组切片和数组数组。但是请注意,在 Go 中 Make 仅用于创建切片(和映射)而不是用于数组...

    x := Make([][2]int, 3)   // a slice of 3 arrays of 2 ints each
    
    // Same thing (except for content)
    y := [][2]int{[2]int{1, 2},
                  [2]int{3, 4},
                  [2]int{5, 6}}
    
    // An array of 3 slices of two ints each
    z := [3][]int{[]int{1, 2},
                  []int{3, 4},
                  []int{5, 6}}
    

    虽然y 和z in the playground 在使用fmt.Println 时看起来相同[[1, 2], [3, 4], [5, 6]],但它们是非常不同的类型,例如您可以使用

    y = append(y, [2]int{7, 8})  // now [[1, 2], [3, 4], [5, 6], [7, 8]]
    

    您可以改为增加z 的第一个元素的长度

    z[0] = append(z[0], 99) // now [[1, 2, 99], [3, 4], [5, 6]]
    

    但是你不能向z添加新元素(它是一个数组),你不能扩展y的元素(因为元素是数组)

    【讨论】:

      【解决方案2】:

      1) 考虑语法,

      a = make([][3]string, 5)
      

      是 5 个切片,每个切片(a[0])是 3 个字符串的数组吗?

      或

      它是单个 slice(a) 指向 5 个数组,每个数组包含 3 个字符串吗?

      它是一个包含 5 个元素的切片,每个元素是一个由 3 个字符串组成的数组。

      2)

      我如何知道元素的类型?切片还是数组?

      切片和数组是不同的类型。您不能互换地将数组和切片分配给同一个变量,因此如果声明将其声明为数组,则为数组,如果将其声明为切片,则为切片。如果括号中有 数字 ([5]string),则为数组,如果括号为空 ([]string),则为切片。

      2) 对于切片声明,

      var b [][3][6]string
      

      创建一个 slice(b) 指向 3 个数组,每个数组包含 6 个字符串, 其中 len(b) = 3 和 cap(b) =3

      b = make([][3][6]string, 5)
      

      创建 5 个切片,其中每个切片(例如 b[0])指向 3 个数组,每个数组包含 6 个字符串

      没有。以前的代码只是声明了一个变量,它还没有保存切片。后面的代码用 五个 元素创建 一个 切片。

      【讨论】:

      • 当你说,一个5个元素的切片,是不是意味着每个元素也是一个切片?
      • 每个元素是一个由 3 个字符串组成的数组,[3]string。
      • b 是具有 5 个元素的单个切片,其中每个元素(例如 b[0])指向类型为 [3]string 的内存。这是否意味着,##1) 元素类型(b[0]) 是 []string 或 ##2) b[0] 是 []string 类型的切片指向 [3]string? 类型的内存?
      • 如果b 是[][3]string,那么b[0] 是[3]string 而b[0][0] 是string。
      • 好的。由于b[0] 是[3]string 类型,b[0] 不是切片
      猜你喜欢
      • 2012-11-10
      • 2023-02-24
      • 1970-01-01
      • 2020-10-31
      • 1970-01-01
      • 1970-01-01
      • 2016-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多