Golang反射包”不是一个类型”。

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

Golang reflect package "is not a type"

问题

我正在尝试学习接口以及如何编写一个可以处理不同类型的单个函数。我想出了一个例子,其中我要找到一个int切片或float32切片中的最大值。代码如下所示。我一直收到错误信息“t不是一个类型”。请问有人可以告诉我出了什么问题,以及我应该如何修复它?

package main

import "fmt"
import "reflect"

var _ = fmt.Println
var _ = reflect.TypeOf

func maxer(s interface{}) interface{} {
	v := reflect.ValueOf(s)
	t := v.Type()

	maxval := s.(t)[0]
	for _, v := range s.(t)[1:] {
		if v > maxval {
			maxval = v
		}
	}
	return maxval
}

func main() {
	fmt.Println(maxer([]int{1, 2, 3, 4}))
	fmt.Println(maxer([]float32{1.1, 2.1, 3.14, 0.1, 2.4}))
}

你的代码中出现了错误。在这里,你试图使用t作为类型来访问切片s的元素。然而,这是不允许的,因为t是一个变量,而不是一个类型。要解决这个问题,你可以使用类型断言来获取切片的实际类型,并使用反射来访问切片的元素。下面是修复后的代码:

package main

import "fmt"
import "reflect"

var _ = fmt.Println
var _ = reflect.TypeOf

func maxer(s interface{}) interface{} {
	v := reflect.ValueOf(s)
	t := v.Type()

	maxval := v.Index(0).Interface()
	for i := 1; i < v.Len(); i++ {
		elem := v.Index(i).Interface()
		switch elem := elem.(type) {
		case int:
			if elem > maxval.(int) {
				maxval = elem
			}
		case float32:
			if elem > maxval.(float32) {
				maxval = elem
			}
		}
	}
	return maxval
}

func main() {
	fmt.Println(maxer([]int{1, 2, 3, 4}))
	fmt.Println(maxer([]float32{1.1, 2.1, 3.14, 0.1, 2.4}))
}

修复后的代码使用了反射来获取切片的元素,并使用类型断言来比较不同类型的元素。这样,你就可以在一个函数中处理不同类型的切片了。希望对你有帮助!

英文:

I'm trying to learn interfaces and how I can write a single function to work with different types. I came up with this example where I'm finding the maximum value in either a slice of int or a slice of float32. The code is as follows. I keep getting this error "t is not a type". Could someone please tell me what is wrong and how I might go about fixing it?

package main

import &quot;fmt&quot;
import &quot;reflect&quot;

var _ = fmt.Println
var _ = reflect.TypeOf

func maxer(s interface{}) interface{} {
	v := reflect.ValueOf(s)
	t := v.Type()

	maxval := s.(t)[0]
	for _, v := range s.(t)[1:] {
		if v &gt; maxval {
			maxval = v
		}
	}
	return maxval
}

func main() {
	fmt.Println(maxer([]int{1, 2, 3, 4}))
	fmt.Println(maxer([]float32{1.1, 2.1, 3.14, 0.1, 2.4}))

答案1

得分: 1

我认为在这种情况下,你最终需要手动处理不同的类型。据我所知,类型断言必须在编译时是真实的类型。这是我在playground上的最佳尝试:http://play.golang.org/p/J8RdHF2MVV

英文:

I think you're going to end up needing to manually handle different types in this case. AFAIK, type assertions must be real types at compile time. Here's my best try in play: http://play.golang.org/p/J8RdHF2MVV

答案2

得分: 1

我正在尝试学习接口以及如何编写一个可以处理不同类型的单个函数。

如果你想简化问题,可以避免使用整个反射包,只需为你的特定目的定义一个接口,以及实现该接口的类型。类似这样:

package main

import "fmt"
import "math"

// 自定义类型
type IntArray []int
type Float32Array []float32

// IntArray 类型的 Max 方法
func (a IntArray) Max() float64 {
    max := math.MinInt32
    for i := 0; i < len(a); i++ {
        if a[i] > max {
            max = a[i]
        }
    }
    return float64(max)
}

// Float32Array 类型的 Max 方法
func (a Float32Array) Max() float64 {
    max := float32(-1 * math.MaxFloat32)
    for i := 0; i < len(a); i++ {
        if a[i] > max {
            max = a[i]
        }
    }
    return float64(max)
}

// 定义一个接口,该接口适用于任何包含返回 float64 的 Max 方法的类型
type Maxing interface {
    Max() float64
}

// 定义一个函数,该函数接受实现了 Maxing 接口的类型
func maxer(m Maxing) float64 {
    return m.Max()
}

func main() {
    // 声明一个新的 IntArray
    i := IntArray([]int{1, 2, 3})

    // 声明一个新的 Float32Array
    f := Float32Array([]float32{1.0, 2.0, 3.0})

    // 使用实现了 Max 接口的任何类型与 maxer 函数一起使用
    fmt.Printf("maxer(IntArray)     = %f\n", maxer(i))
    fmt.Printf("maxer(Float32Array) = %f\n", maxer(f))
}

这段代码定义了两个自定义类型 IntArrayFloat32Array,它们分别实现了 Max 方法。然后定义了一个接口 Maxing,该接口要求实现一个返回 float64Max 方法。最后,定义了一个函数 maxer,该函数接受实现了 Maxing 接口的类型,并调用其 Max 方法。

main 函数中,我们创建了一个 IntArray 和一个 Float32Array,并将它们作为参数传递给 maxer 函数进行计算。

英文:

> I'm trying to learn interfaces and how I can write a single function to work with different types.

then it's probably simpler to avoid the whole reflection package, and just define an interface for your specific purpose.. and types that implement your interface. something like this:

package main

import &quot;fmt&quot;
import &quot;math&quot;


// Homegrown types
type IntArray []int
type Float32Array []float32


// Max defined for type IntArray
func (a IntArray) Max() float64 {
    max := math.MinInt32;
    for i := 0; i &lt; len(a); i++ {
        if a[i] &gt; max {
            max = a[i]
        }
    }
    return float64(max)
}


// Max defined for type Float32Array
func (a Float32Array) Max() float64 {
    max := float32(-1 * math.MaxFloat32)
    for i := 0; i &lt; len(a); i++ {
        if a[i] &gt; max {
            max = a[i]
        }
    }
    return float64(max)
}


// Define an interface that works for any type
// containing a Max function returning a float64 
type Maxing interface {
    Max() float64
}


// Define a function that works with your interface type
func maxer(m Maxing) float64 {
    return m.Max();
}


func main(){

    // Declare a new IntArray
    i := IntArray([]int{1,2,3})

    // Declare a new Float32Array
    f := Float32Array([]float32{1.0,2.0,3.0})

    // Use any type implementing the Max interface with the &#39;maxer&#39; func
    fmt.Printf(&quot;maxer(IntArray)     = %f\n&quot;, maxer(i));
    fmt.Printf(&quot;maxer(Float32Array) = %f\n&quot;, maxer(f));

}

答案3

得分: 0

类似于bjarneh的回答。如果你想通过接口来实现这个功能,最好避免使用反射。反射对于比较值来说并不好,因为你无法知道值的类型。

我的建议是实现类似于Go语言的排序接口(sort.Interface),它允许你在任何类型上使用sort函数。

通过这种方式实现,你就可以获取结构体或字符串的最大值,只要你为它们实现了相应的函数。

在Go Playground上的代码示例:

package main

import (
	"fmt"
)

type Comparable interface {
	Less(i, j int) bool
	Len() int
	Val(i int) interface{}
}

func maxer(s Comparable) interface{} {
	if s.Len() == 0 {
		return nil
	}
	maxI := 0
	for i := 1; i < s.Len(); i++ {
		if s.Less(maxI, i) {
			maxI = i
		}
	}
	return s.Val(maxI)
}

type MaxerInt []int

func (m MaxerInt) Len() int           { return len(m) }
func (m MaxerInt) Val(i int) interface{} { return m[i] }
func (m MaxerInt) Less(i, j int) bool { return m[i] < m[j] }

type MaxerFloat []float64

func (m MaxerFloat) Len() int           { return len(m) }
func (m MaxerFloat) Val(i int) interface{} { return m[i] }
func (m MaxerFloat) Less(i, j int) bool { return m[i] < m[j] }

func main() {
	fmt.Println(maxer(MaxerInt{1, 2, 3, 4}))
	fmt.Println(maxer(MaxerFloat{1.1, 2.1, 3.14, 0.1, 2.4}))
}

希望对你有帮助!

英文:

Similar to bjarneh's response. If you want to do this via interfaces, best to avoid reflect. Reflect is not good for comparing values, because you cannot know what type the values are.

My suggestion is to implement something similar to go's sort interface which allows you to use the function sort on any type.

Implementing it this way would then allow you to get max value for structs or strings, as long as you implemented the functions for them.

On go playgorund

package main

import (
	&quot;fmt&quot;
)

type Comparable interface {
	Less(i, j int) bool
	Len() int
	Val(i int) interface{}
}

func maxer(s Comparable) (interface{}) {
	if s.Len() == 0 {
		return nil
	}
	maxI := 0
	for i := 1; i &lt; s.Len(); i++ {
		if s.Less(maxI, i) {
			maxI = i
		}
	}
	return s.Val(maxI)
}

type MaxerInt []int
func (m MaxerInt) Len() int {return len(m)}
func (m MaxerInt) Val(i int) interface{} {return m[i]}
func (m MaxerInt) Less(i, j int) bool {return m[i] &lt; m[j]}

type MaxerFloat []float64
func (m MaxerFloat) Len() int {return len(m)}
func (m MaxerFloat) Val(i int) interface{} {return m[i]}
func (m MaxerFloat) Less(i, j int) bool {return m[i] &lt; m[j]}

func main() {
	fmt.Println(maxer(MaxerInt{1, 2, 3, 4}))
	fmt.Println(maxer(MaxerFloat{1.1, 2.1, 3.14, 0.1, 2.4}))
}

huangapple
  • 本文由 发表于 2014年1月5日 13:27:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/20930447.html
匿名

发表评论

匿名网友

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

确定