如何在Go语言中创建对内置类型的别名的字面切片?

huangapple go评论79阅读模式
英文:

How to create a literal slice of an alias to a builtin type in Go

问题

我有一些操作接口类型(Comparable)的 golang 代码。为了测试我的代码,我想创建一些虚假数据并对其进行操作。然而,我在不费力的情况下做到这一点遇到了困难。我唯一能想到的做法是为测试创建一个新类型(在这种情况下是 int 的别名),满足 Comparable 接口的要求,然后将这个类型的字面量切片传递给我的测试。我设想它看起来像下面这样:

type Comparable interface {
    LT(Comparable) bool
    AsFloat() float64
} 

type testInt int 

func (self testInt) LT(other Comparable) bool { 
    return float64(self) < other.AsFloat() 
} 

func (self testInt) AsFloat() float64 { 
    return float64(self) 
} 

func TestAFunction(t *testing.T) { 
    FunctionToTest([]Comparable{7, 4, 2, 1})
    ....
}

然而,使用这个示例,编译器会报错,说 int 类型不能用作 Comparable。我理解为什么会发生这种情况,但我不知道如何解决它。首先,我不知道如何创建 testInt 类型的字面量。其次,我必须编写大量这样的函数。对于我的目的来说,使用字面量 int 更加方便。

有没有一种方法可以使用内置类型的类型别名,以便编译器可以正确推断出具有最少代码的字面量的正确类型?

此外,也许有更好的方法来实现我想做的事情,即生成满足测试中使用的接口的硬数据吗?

英文:

I have some golang code that manipulates slices of an interface type (Comparable). To test my code, I want to create some fake data and operate on it. However, I'm having trouble doing this in a way that is not incredibly tedious. The only thing I can think to do is create a new type for testing (in this case an alias of type int) that satisfies the Comparable interface, and then feed my tests literal slices of that type. I envision it looking something like the following:

type Comparable interface {
    LT(Comparable) bool
    AsFloat() float64
} 

type testInt int 
 
func (self testInt) LT(other Comparable) bool { 
    return float64(self) &lt; other.AsFloat() 
} 
 
func (self testInt) AsFloat() float64 { 
    return float64(self) 
} 
 
func TestAFunction(t *testing.T) { 
    FunctionToTest([]Comparable{7, 4, 2, 1})
    ....
}

However, with this example, the compiler will complain that type int cannot be used as a Comparable. I understand why this is happening, but I'm not sure how to solve it. First, I don't know how to create a literal of type testInt. Second, I have to write a significant number of these functions. Working with literal ints is far more convenient for my purposes.

Is there a way to work with type aliases of builtin types such that the compiler can correctly infer the correct type of literals with a minimum of code?

Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?

答案1

得分: 4

以下是代码的中文翻译:

func NewWhatevers(a ...int) (r []Whatever) {
    r = make([]Whatever, len(a))
    for i, v := range a {
        r[i] = Whatever(v)
    }
    return
}

...

myWhatevers := NewWhatevers(7, 4, 2, 1)
func NewWhatevers(a ...int) (r []Whatever) {
    // 创建一个长度为a的切片r
    r = make([]Whatever, len(a))
    // 遍历a切片,将每个元素转换为Whatever类型,并赋值给r切片对应位置
    for i, v := range a {
        r[i] = Whatever(v)
    }
    return
}

...

// 调用NewWhatevers函数,并传入参数7, 4, 2, 1
myWhatevers := NewWhatevers(7, 4, 2, 1)
英文:
func NewWhatevers(a ...int) (r []Whatever) {
        r = make([]Whatever, len(a))
        for i, v := range a {
                r[i] = Whatever(v)
        }
        return
}

...

myWhatevers := NewWhatevers(7, 4, 2, 1)

答案2

得分: 2

有几种方法可以实现这个。问题如你所说,Go编译器无法自动将int转换为Comparable(因为这将需要找到所有可能的等效类型,并确定哪些等效类型满足Comparable接口,如果有多个...你明白了)。因此,你需要做以下两件事之一:

写一个显式的类型转换:

FunctionToTest([]Comparable{ testInt(7), testInt(4), testInt(2), testInt(1) })

然而,如果你需要很多字面量,这可能会变得非常麻烦。因此,你还可以:

编写一个将[]int转换为[]Comparable的函数:

func intToComparable(i []int) []Comparable {
    c := make([]Comparable, len(i))
    for i, v := range i {
        c[i] = testInt(v)
    }
    return c
}

然后你只需要:

FunctionToTest(intToComparable([]int{ 7, 4, 2, 1 }))
英文:

There are a number of ways to accomplish this. The problem, as you correctly state, is that the Go compiler cannot automatically convert int to Comparable (since doing so would require finding all possible equivalent types, and figuring out which of those equivalent types satisfy the Comparable interface, and then if there are more than one... you get the idea). Thus, you'll have to do one of two things:

Write an explicit type conversion:

FunctionToTest([]Comparable{ testInt(7), testInt(4), testInt(2), testInt(1) })

However, if you need a lot of literals, this could get really annoying. Thus, you could also:

Write a function to convert []int to []Comparable:

func intToComparable(i []int) []Comparable {
    c := make([]Comparable, len(i))
    for i, v := range i {
        c[i] = testInt(v)
    }
    return c
}

and then you'd only have to do:

FunctionToTest(intToComparable([]int{ 7, 4, 2, 1 }))

答案3

得分: 1

此外,也许有更好的方法来实现我想要做的事情,即生成满足测试使用的接口的硬数据吗?

也许有。你遇到的问题是[]Comparable[]testInt是根本不同的,不能在内存中作为底层表示进行交换。
如果你的代码不仅仅是关于可比较的单个项,而是关于可以比较的项的切片,那么你可以重构你的代码来处理整个切片。

看看sort包是如何做到这一点的:它不是在可比较的切片上操作,而是在一个"可比较切片"上操作。

// FloatOrder是一个具有可比较和可转换为浮点数元素的切片
type FloatOrder interface {
    Less(i, j int) bool  // 比较元素i和j,并返回true,如果第一个元素小于另一个元素
    Float(i int) float64 // 将元素i作为float64返回
}

type testInts []int
func (n testInts) Less(i, j int) bool {return n[i] < n[j]}
func (n testInts) Float(i int) float64 { return float64(n[i]) }

func FunctionTotest(fo FloatOrder) { ... }

func TestAFunction(t *testing.T) { 
       FunctionToTest(testInts{1,2,3,4})
       ....
}

(完全未经测试,仅用于说明的代码)

英文:

> Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?

Maybe. The problem you encountered is that []Comparable and []testInt are fundamentally different and cannot be exchanged as the underlying representation in memory is different.
If your code is less about individual item which are Comparable but more about slices of items which can be compared than you could refactor your code to work on whole Slices.

Have a look at how package sort does this: It doesn't operate on a slice of comparables but on a "comparable slice".

// FloatOrder is a slice with comparable and float-convertible elements 
type FloatOrder interface {
    Less(i, j int) bool  // Compare element i and j and return true first is less than the other
    Float(i int) float64 // Return element i as a float64
}

type testInts []int
func (n testInts) Less(i, j int) bool {return n[i] &lt; n[j]}
func (n testInts) Float(i int) float64 { return float64(n[i]) }

func FunctionTotest(fo FloatOrder) { ... }

func TestAFunction(t *testing.T) { 
       FunctionToTest(testInts{1,2,3,4})
       ....
}

(Completely untested, illustration-only code)

huangapple
  • 本文由 发表于 2013年8月6日 15:47:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/18074464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定