golang中的常规切片类型?

时间:2014-06-18 04:47:56

标签: types go slice

我在尝试将切片类型扩展为Go中的常规类型时遇到了一些困难。我已经创建了一个示例代码来解释我的问题。 play ground version

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类型的变量不能被切片:

  

无法切片c(类型序列发生器)

有没有办法定义一般类型的切片(int,float64,string,...)而不隐藏切片的酷索引功能?

3 个答案:

答案 0 :(得分:5)

你有

type Sequencer interface {
    Mean() float64
}

c := Sequencer(b)

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

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())
}

输出:

2.5
1.5
2.5
1.5
2.929795

答案 1 :(得分:4)

提供接口定义中声明的方法的任何类型都可以存储在该类型的接口变量中。虽然您存储的实际值是一个切片,但任何类型都可以实现该接口。并且由于在许多情况下不可能静态地确定接口变量的动态类型,因此在没有明确类型断言的情况下,语言不会让您在封面下方查看。

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

type Sequencer interface {
    Mean() float64
    Slice(start, end int) Sequencer
}

这可以通过显而易见的方式为您的Sequence类型实施:

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

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

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

您可以在此处试用此解决方案:http://play.golang.org/p/UMuqOarLUu

答案 2 :(得分:2)

当然。这与具有接口概念的任何其他语言没有什么不同。

您尝试在不支持它的类型上调用“运算符”[] - Sequencer(接口)。然而,Sequence确实 - 因为它具有切片的属性,因此调用b.Meanb[:]的工作原理。

如果这是C#,例如,你实际上是在尝试这个:

interface Sequencer {
    float Mean();
}

Sequencer c = ...;

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

这里的限制是你不能在Go中实现运算符重载。如果你可以 - 那么你就可以将它添加到界面中,并且所有内容都会按照预期进行操作。