在不惊慌的情况下访问 Go 切片

Accessing a Go slice without panicking

提问人:beep 提问时间:8/25/2023 更新时间:9/11/2023 访问量:108

问:

当切片没有足够的元素时,如何才能在不惊慌的情况下访问切片?

我有以下代码:

str = str[:3]

但是由于它的内容长度可能会有所不同,因此当它少于 3 个元素时,它会使整个程序崩溃。有什么方法可以忽略它吗?在 Javascript 中,我可以在没有这个问题的情况下使用该方法。例如:slice

str = str.slice(0, 3);

即使长度小于 3,也会将字符串切成薄片。

切片

评论

3赞 icza 8/25/2023
在尝试切片之前,请检查切片的容量:.if cap(s) >= 3 { str = str[:3] }
0赞 mjrezaee 8/25/2023
您可以简单地检查切片大小,因为我假设您只需要在切片中插入有效的数据:lenif len(s) >= 3 { str = str[:3] }

答:

2赞 jub0bs 8/25/2023 #1

如果一个模拟 JavaScript 切片方法行为的函数对你来说很方便,你可以很容易地编写一个通用的 (Go 1.21+) 函数:

package main

import "fmt"

func main() {
    s := []int{1, 2, 3}
    fmt.Println(Slice(s, 1, 4))  // output: [2, 3]
    fmt.Println(Slice(s, 2, 1))  // output: []
    fmt.Println(Slice(s, 5, 7))  // output: []
    fmt.Println(Slice(s, -2, 1)) // output: [1]
}

func Slice[S ~[]T, T any](s S, lo, hi int) S {
    if hi <= lo {
        return nil
    }
    lo = clip(0, lo, cap(s))
    hi = clip(0, hi, cap(s))
    return s[lo:hi]
}

func clip(lo, a, hi int) int {
    return max(lo, min(a, hi))
}

(操场)


如果由于某种原因,您还不能迁移到 Go 1.21+,这里有一个与 Go 1.18+ 兼容的版本:

package main

import "fmt"

func main() {
    s := []int{1, 2, 3}
    fmt.Println(Slice(s, 1, 4))  // output: [2, 3]
    fmt.Println(Slice(s, 2, 1))  // output: []
    fmt.Println(Slice(s, 5, 7))  // output: []
    fmt.Println(Slice(s, -2, 1)) // output: [1]
}

func Slice[S ~[]T, T any](s S, lo, hi int) S {
    if hi <= lo {
        return nil
    }
    lo = clip(0, lo, cap(s))
    hi = clip(0, hi, cap(s))
    return s[lo:hi]
}

func clip(lo, a, hi int) int {
    return max(lo, min(a, hi))
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

(操场)

评论

1赞 icza 8/25/2023
如果这样称呼,这会惊慌失措:SafelySlice([]int{1, 2, 3}, 2, 1)
1赞 jub0bs 8/25/2023
@icza确实如此!谢谢。固定。