The content on this page is written in Chinese, and then traslated into English by machine. More accurate traslations are welcome at: https://github.com/wa-lang/man/tree/master/en

Ending's law: "Any application that can be compiled to WebAssembly, will be compiled to WebAssembly eventually."

5.3. Slice

The basic declaration of the slice type is as follows, T is the element type:

[]T

The first impression of slices is very similar to arrays: they are both sequences of objects of a specific type, but there is a huge difference in their actual behavior. A slice is a partial reference to an array, which is often taken from an array, for example:

    arr := [...]i32{1, 2, 3, 4}
    sl: []i32 = arr[0:2]
    println(len(sl))      // 2
    println(sl[0], sl[1]) // 1 2

The expression arr[m:n] returns a slice, starting from the m element of the array arr, with a slice length of n-m, similar to the syntax of a string. If m is omitted, It means starting from the first element of the array; if n is omitted, it means ending at the last element of the array. m and n must not exceed the actual range of the array, otherwise an exception will be triggered.

The actual data is not stored in the slice, the object accessed through [] is located in the array it refers to, which means that changing the object in the array may affect the slice and vice versa, for example:

    arr := [...]i32{1, 2, 3, 4}
    sl := arr[0:2]
    println(sl[0]) // 1
    arr[0] = 13
    println(sl[0]) // 13
    sl[1] = 42
    println(arr[1]) // 42

The built-in function cap can be used to obtain the available capacity of a slice - the length of the array referenced by the slice minus the starting position of the slice, for example:

    arr := [...]i32{11, 12, 13, 14}
    sl1 := arr[1:2]
    println(len(sl1), cap(sl1)) // 1 3

By definition, the capacity of a slice is always greater or equal to its length.

An array can be referenced by multiple slices. If there is overlap between the referenced parts, changes to the overlapping parts will also affect each other, for example:

    arr := [...]i32{1, 2, 3, 4}
    sl1 := arr[0:2]
    sl2 := arr[1:3]
    println(sl2[0]) // 2
    sl1[1] = 42
    println(sl2[0]) // 42

In fact, using the [m:n] operator on a slice can also get a new slice, starting from the mth element of the source slice. The rest of the rules are similar to getting a slice from an array.

In addition to referencing arrays or existing slices, slices can also be created directly through the built-in function make. The general syntax is:

make([]T, Len: int, Cap: int) => []T
make([]T, Len: int) => []T // Equivalent to make([]T, Len, Len)

The return value is a slice of type []T, length Len, and capacity Cap, where Cap can be omitted, and the capacity of the slice is Len, for example:

    sl1 := make([]i32, 3, 5)
    println(sl1[0], len(sl1), cap(sl1)) // 0 3 5

When using the make function to create a slice, an array of length Cap is implicitly created and referenced as the slice.

Another built-in function related to slicing is append, which is used to append elements to a slice. The general syntax is:

append(sl []T, e T) => []T

This function appends element e to the end of slice s and returns a new slice. Since function calls in Wa-lang use value passing, the appending behavior will not affect the source slice s, so the actual commonly used writing method is as follows:

    sl: []i32
    //...
    sl = append(sl, 42)

That is, assign the new slice returned by append to the source slice. append not only appends elements to a slice, but also appends another slice, for example:

    sl1 := []i32{13, 42}
    sl2 := []i32{9527, 1024}
    sl1 = append(sl1, sl2...)
    println(sl1[0], sl1[1], sl1[2], sl1[3]) // 13 42 9527 1024

When the appended object is a slice, ... should be added after the variable name.

Since the slice refers to an array with a fixed length, if the length of the slice does not exceed the available capacity of the array after appending an element using append, then the contents of the corresponding element of the array will be replaced by the appended element, for example:

    arr := [...]i32{1, 2, 3}
    sl1 := arr[0:2]
    sl1 = append(sl1, 5)
    println(arr[2]) // 5    

If the length of the new slice exceeds the capacity of the original array, the append function will automatically re-apply for a large enough array, copy the elements of the source slice to the new array (a deep copy is automatically performed), and then perform the append. This situation is called slice expansion, for example:

    arr := [...]i32{1, 2, 3}
    sl1 := arr[:]
    sl2 := append(sl1, 4)
    sl2[0] = 42
    println(sl1[0]) // 1

Obviously, if a slice expansion occurs, the mutual reference between the new slice and the source slice is severed.

Different from the data types introduced in the previous chapter, variables of the slice type are not comparable because slices are not pure value types, but have a reference relationship with the underlying array or even other slices, which makes the slice unable to guarantee that the element values ​​in it are unchanged.

Slices can only be compared with the constant nil, which is used to determine whether the slice has a value of 0, for example:

    sl: []i32
    println(sl == nil, sl != nil) // true false

In fact, if you need to determine whether a slice is empty, you should not compare it with nil, but determine whether its length is 0, because there are slices with length 0 but not nil, for example:

    arr := [...]i32{1, 2, 3}
    sl1 := arr[0:0]
    println(sl1 == nil, len(sl1), cap(sl1)) // false 0 3

Unless otherwise noted, Wa-lang programs should handle slices of length 0 in the same way as slices of nil values. The built-in function append meets this requirement. For example, the following program is legal:

    sl: []i32 // sl == nil
    sl := append(sl, 5)
    println(sl[0]) // 5

Known issues:

  • Bounds checking is not performed when accessing slice elements. This problem does not affect syntax compatibility. Subsequent corrections to this problem will not affect the existing source code. Developers using Wa-lang do not need to deal with this issue specially.
  • No bounds checking was performed when using [] to get a new slice from an array or slice. This problem does not affect syntax compatibility. Subsequent corrections to this problem will not affect the existing source code. Developers using Wa-lang do not need to deal with this issue specially.