关于go:golang中的常规切片类型?

General slice type in golang?

我在尝试将切片类型扩展为Go中的一般类型时遇到了一些困难。我创建了一个示例代码来解释我的问题。Play Ground版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import"fmt"

type Sequencer interface {
    Mean() float64
}

type Sequence []int

func (s Sequence) Mean() float64 {
    sum := 0.0
    for _, el := range s {
        sum += float64(el)
    }
    return sum / float64(len(s))
}

func main() {
    a := []int{1, 2, 3, 4}
    b := Sequence(a)
    fmt.Println(b.Mean())
    fmt.Println(b[:2].Mean())
    c := Sequencer(b)
    fmt.Println(c.Mean())
    fmt.Println(c[:2].Mean())
}

main()函数的最后一行返回一个错误,说明不能切片Sequencer类型的变量:

cannot slice c (type Sequencer)

有没有一种方法可以定义一般类型的切片(int、float64、string等),而不隐藏切片的酷索引功能?


你有

1
2
3
4
5
type Sequencer interface {
    Mean() float64
}

c := Sequencer(b)

因此,变量c包含满足Sequencer接口的某种类型的值;该类型具有Mean方法。我们只能说,不多不少。这并不意味着变量c值可以被切片。因此,切片表达式c[:2]无效。例如,我们可以定义一个满足Sequencer接口但不能切片的Map类型。如果您想切片c,那么断言它是可以切片的类型,例如,c.(Sequence)[:2]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import"fmt"

type Sequencer interface {
    Mean() float64
}

type Sequence []int

func (s Sequence) Mean() float64 {
    sum := 0.0
    for _, el := range s {
        sum += float64(el)
    }
    return sum / float64(len(s))

}

type Map map[string]float64

func (m Map) Mean() float64 {
    sum := 0.0
    for _, v := range m {
        sum += float64(v)
    }
    return sum / float64(len(m))

}

func main() {
    a := []int{1, 2, 3, 4}
    b := Sequence(a)
    fmt.Println(b.Mean())
    fmt.Println(b[:2].Mean())
    c := Sequencer(b)
    fmt.Println(c.Mean())
    fmt.Println(c.(Sequence)[:2].Mean())
    m := Map{"one": 3.14159,"two": 2.718}
    fmt.Println(m.Mean())
}

输出:

1
2
3
4
5
2.5
1.5
2.5
1.5
2.929795


提供接口定义中声明的方法的任何类型都可以存储在该类型的接口变量中。当您存储的实际值是一个切片时,任何类型都可以实现该接口。而且,由于在许多情况下,静态地确定接口变量的动态类型是不可能的,因此在没有显式类型断言的情况下,该语言不允许您浏览封面下面的内容。

如果您希望实现Sequencer类型的类型实现切片,那么简单的解决方案是扩展接口以包含这样的方法:

1
2
3
4
type Sequencer interface {
    Mean() float64
    Slice(start, end int) Sequencer
}

这可以以明显的方式为您的Sequence类型实现:

1
2
3
func (s Sequence) Slice(start, end int) Sequencer {
    return s[start:end]
}

然后可以使用以下方法获得切片的平均值:

1
fmt.Println(c.Slice(0, 2).Mean())

你可以在这里试验这个解决方案:http://play.golang.org/p/umuqoarluu


当然。这与任何其他具有接口概念的语言都没有区别。

您试图在不支持它的类型上调用"operator"[]Sequencer(接口)。然而,Sequence确实如此——因为它具有一个切片的属性,所以为什么对b.Meanb[:]的调用会起作用。

例如,如果这是C,您实际上是在尝试:

1
2
3
4
5
6
7
interface Sequencer {
    float Mean();
}

Sequencer c = ...;

c[any_index] ... // error - interface doesn't have this operator defined

这里的限制是不能在go中实现运算符重载。如果可以的话,那么您就可以将它添加到接口中,并且所有的操作都会按预期进行。