简体   繁体   English

golang中的常规切片类型?

[英]General slice type in golang?

I'm having some difficulties trying to extend slice types into a general type in Go. 我在尝试将切片类型扩展为Go中的常规类型时遇到了一些困难。 I have created a sample code to explain my problem. 我已经创建了一个示例代码来解释我的问题。 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())
}

Last line of the main() function returns an error saying that variables of type Sequencer cannot be sliced: main()函数的最后一行返回一个错误,指出Sequencer类型的变量不能被切片:

cannot slice c (type Sequencer) 不能切片c(类型序列器)

Is there a way of defining a general type of slices (int, float64, string,...) without hiding the cool indexing capabilities of slices? 有没有一种方法可以定义一般类型的切片(int,float64,string,...)而不隐藏切片的很酷的索引功能?

You have 你有

type Sequencer interface {
    Mean() float64
}

c := Sequencer(b)

Therefore, the variable c contains a value of some type which satisfies the Sequencer interface; 因此,变量c包含满足Sequencer接口的某种类型的值; the type has a Mean method. 该类型具有Mean方法。 That's all we can say, no more, no less. 这就是我们所能说的,不多也不少。 It does not imply that the variable c value can be sliced. 这并不意味着可以切片变量c值。 Therefore, the slice expression c[:2] is invalid. 因此,切片表达式c[:2]无效。 For example, we could define a type Map which satisfies the Sequencer interface but cannot be sliced. 例如,我们可以定义一个类型Map ,它满足Sequencer接口但不能被切片。 If you want to slice c then assert that it is of a type that can be sliced, for example, c.(Sequence)[:2] . 如果你想切片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())
}

Output: 输出:

2.5
1.5
2.5
1.5
2.929795

Any type that provides the methods declared in an interface definition can be stored in an interface variable of that type. 提供接口定义中声明的方法的任何类型都可以存储在该类型的接口变量中。 While the actual value you are storing is a slice, any type could implement the interface. 虽然您存储的实际值是一个切片,但任何类型都可以实现该接口。 And since in many cases it is impossible to statically determine the dynamic type of an interface variable, the language doesn't let you peek below the covers without an explicit type assertion. 并且由于在许多情况下不可能静态地确定接口变量的动态类型,因此如果没有显式的类型断言,语言不会让您在封面下面查看。

If slicing is something you expect types implementing your Sequencer type to implement, then the simple solution is to extend the interface to include such a method: 如果切片是您期望实现Sequencer类型的类型实现的,那么简单的解决方案是扩展接口以包含这样的方法:

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

This can be implemented for your Sequence type in the obvious way: 这可以通过显而易见的方式为您的Sequence类型实现:

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

You can then get the mean of a slice using the method: 然后,您可以使用以下方法获取切片的平均值:

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

You can experiment with this solution here: http://play.golang.org/p/UMuqOarLUu 您可以在此处试验此解决方案: http//play.golang.org/p/UMuqOarLUu

Of course. 当然。 This is no different from any other language that has the concept of an interface. 这与具有接口概念的任何其他语言没有什么不同。

You're trying to call the "operator" [] on a type that doesn't support it - Sequencer (an interface). 你试图在一个不支持它的类型上调用“operator” [] - Sequencer (一个接口)。 Whereas, Sequence does - because it takes on the properties of a slice, hence why the calls to b.Mean and b[:] work. 然而, Sequence确实 - 因为它具有切片的属性,因此对b.Meanb[:]的调用起作用。

If this were C# for example, you're essentially trying this: 如果这是C#,例如,你实际上是在尝试这个:

interface Sequencer {
    float Mean();
}

Sequencer c = ...;

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

The limitation here is that you cannot implement operator overloads in Go. 这里的限制是你不能在Go中实现运算符重载。 If you could - then you would be able to just add that to the interface and all would tick along as expected. 如果可以 - 那么你就可以将它添加到界面中,并且所有内容都会按预期方式进行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM