切片

Slicing a slice

问题描述: 我有一片 bar。如果 bar 中至少有 2 个元素,我想用 bar 的前两个元素创建另一个切片 foo。或者如果 bar 至少有一个元素,则使用 bar 的第一个元素。

我的想法:

// bar := []int{1, 2, 3...
foo := bar[:(int)(math.Min(float64(len(bar)), 2))]

编辑: 这是我尝试过的另一种方法,

x := 2
if len(bar) < 2 {
    x = len(bar)
}
foo := bar[:x]

是否可以改进代码?至少,投两次来实现如此简单的事情对我来说并不好看。

只需使用一个 if。它更具可读性和性能,因为 intfloat64.

之间没有转换
var foo []int
if len(bar) > 1 {
    foo = bar[:2]
} else {
    foo = bar[:len(bar)]
}

Go 没有 math.MinInt。但是实现一个很简单:

func Min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

...

foo := bar[:Min(len(bar), 2)]
bar := []int{}
n := len(bar)
if n > 2 {
    n = 2
}
foo := bar[:n]
fmt.Printf("%v", foo)

适用于 len(bar) = 0, 1, 2, n.. Playground sample

任意数量元素的通用(如您在评论中所问)函数:

func strip(s []int, n int) []int {
    if len(s) < n {
        n = len(s)
    }
    return s[:n]
}

...
foo := strip(bar, 2)

Go Playground example

如果切片的长度大于 2,您可以重新切片。如果不是,无需重新切片,只需在赋值中使用切片本身,这将自动满足您的需求:结果最多包含 2 个元素。

您甚至可以 "spare" ifelse 分支:

foo := bar
if len(foo) > 2 {
    foo = foo[:2]
}

注:

切片是引用类型。因此,即使您使用 bar 初始化 foo,如果您之后修改 foo 变量 (不是切片的元素),那确实不影响bar(赋值时复制参考值):

bar := []int{0, 1, 2, 3}
foo := bar
if len(foo) > 2 {
    foo = foo[:2]
}
fmt.Println(foo) // Here foo is [0, 1] as expected

foo = foo[:1]    // Reslicing foo
fmt.Println(bar) // Bar is unaffected, bar = [0 1 2 3]

输出(在 Go Playground 上尝试):

[0 1]
[0 1 2 3]