Understanding Simple Slice Expressions in the Go Language (s[n:m])

Asked 2 years ago, Updated 2 years ago, 59 views

In the code below, (2) is OK, and (3) is a runtime error for what reason? The Go version is "go1.11 darwin/amd64".

package main

import "fmt"

funcmain(){
    a: = "a"
    fmt.Println(a[:len(a)])//(1) "a"
    fmt.Println(a[len(a):])//(2)"
    // fmt.Println(a[len(a)])//(3)panic-index out of range
    // fmt.Println(a[len(a)+1:])//(4)panic-slice bound out of range
}

go

2022-09-30 10:40

2 Answers

I have rarely used Go language, but

  • Valid values for the array index range from 0 to len(a)-1
  • If you specify a range, (leftmost) → index of the starting position, (rightmost) → index of the ending position +1

It's the same when you say .

I think it would be easier to understand if there were more than one element.

package main

import(
    "fmt"
)

funcmain(){
    a: = "abc"
    fmt.Println(len(a))//->3
    fmt.Println(a[0])//->97('a')
    fmt.Println(a[1])//->98('b')
    fmt.Println(a[2])//->99('c')
    // fmt.Println(a[3]) // panic:runtime error:index out of range
    fmt.Println(a[0:])//->abc
    fmt.Println(a[:3])//->abc
    fmt.Println(a[0:3])//->abc
    fmt.Println(a[1:])//->bc
    fmt.Println(a[1:3])//->bc
    fmt.Println(a[2:])//->c
    fmt.Println(a[2:3])//->c
    fmt.Println(a[3:])//->
    fmt.Println(a[3:3])//->
    // fmt.Println(a[4:]) // panic:runtime error:slice bound out of range
}

This is how a (len(a)==3) indexes are assigned.

 | 'a' | 'b' | 'c' | Nothing
 [0] [1] [2] [3]

a[len(a)] (==a[3]) is an error, of course.

Then, on the contrary, a[:len(a)] and a[len(a):] do not fail because there is a second rule above.

a[:len(a)] is the same as a[0:3] when len(a)==3.

 | 'a' | 'b' | 'c' | Nothing
 [0]← From here
             [3]← Up to one serving here

a[3] has no element, but the range is up to one before it, so it means "abc".

Of course, if 3 cannot be specified, the range that represents "all to the end" will not be explicitly written.

Also, since a[0:3] represents "abc", a[1:3] represents "bc", and a[2:3] represents "c", is it very natural that a[3:3] represents an empty string? (You may not think until you get used to it...)

So it's not so much for humans as for the convenience of machines.where 3 is a valid value (although the endpoint must be the same) when representing the starting point of the range.

a[0:]
| 'a' | 'b' | 'c' | Nothing
 [0]← All from here (`abc``)

a [3:]
| 'a' | 'b' | 'c' | Nothing
             [3]← All from here (``````)

In the case of your example, len(a)==1, so it may not make sense, but it's almost the same.

a[:0](==a[:len(a)]
| 'a' | Nothing
     [1]← All before this ("a")
a[0:](==a[len(a):]
| 'a' | Nothing
     [1]← All from here ("")

It's more convenient to specify a range that's hard to understand, but if you gain experience in this way, you'll see it naturally.

Please let me know if there is anything else that is hard to understand.


2022-09-30 10:40

This is not the answer, but I looked into how it works on the source code.

The slice processing is done here at .

slice computers the slice v[i:j:k] and returns ptr, len, and cap of result.i,j,k may binil, in which case they are set to their default value.

As you can see in the comments, a[len(a):] is treated as a[len(a):len(a)] for bound checking.In this case, a is a string, so s.boundsCheck(i,j,ssa.BoundsSliceB,bound) will eventually run.

case t.IsString():
  ptr = s.newValue1 (ssa.OpStringPtr, types.NewPtr (types.Types [TUINT8]), v)
  len=s.newValue1 (ssa.OpStringLen, types.Types [TINT], v)
  cap=len
      :

// Set default values
      :
if j == nil {
  j=len
}
three —= true
ifk == nil {
  three=false
  k = cap
}

// Panic if slice indications are not in bounds.
      :
if three {
      :        
} else{
  if j!=k{
      :        
  }
  i=s.boundCheck(i,j,ssa.BoundsSliceB,bound)
}

ssa.BoundsSliceB is the operational code for boundary checks, but is defined here in .

type BoundsKinduint8

const(
  BoundsIndex BoundsKind = iota//indexing operation, 0<=idx<len failed
               :
  BoundsSliceB//2-arg slicing operation, 0<=low<=high failed

The decision criteria are 0<=low<=high and both low, high are len(a), so it is determined to be within the boundary.

If a[len(a)+1:], low=len(a)+1, high=len(a), it becomes low>high, and you get stuck in the boundary check (panic(bounds out of range)).

If the decision criteria were 0<=low<high, then a[len(a):] would have caused panic.

Incidentally, for index access such as a[len(a)], it is checked with BoundsIndex, so 0<=idx<len is the criterion (a[len(a)] is index of code>).


2022-09-30 10:40

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.