How to iterate over different types in loop in Go?

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

How to iterate over different types in loop in Go?

问题

在Go语言中,要遍历一个数组/切片,你可以这样写:

for _, v := range arr {
    fmt.Println(v)
}

然而,我想要遍历包含不同类型(int、float64、string等)的数组/切片。在Python中,我可以这样写:

a, b, c = 1, "str", 3.14
for i in [a, b, c]:
    print(i)

在Go语言中,如何实现这样的功能呢?据我所知,数组和切片都只允许相同类型的对象,对吗?(比如,[]int 只允许 int 类型的对象。)

谢谢。

英文:

In Go, in order to iterate over an array/slice, you would write something like this:

for _, v := range arr {
    fmt.Println(v)
}

However, I want to iterate over array/slice which includes different types (int, float64, string, etc...). In Python, I can write it out as follows:

a, b, c = 1, "str", 3.14
for i in [a, b, c]:
    print(i)

How can I do such a work in Go? As far as I know, both array and slice are supposed to allow only same-type object, right? (say, []int allows only int type object.)

Thanks.

答案1

得分: 5

由于Go是一种静态类型语言,所以这并不像Python那样容易。你将不得不使用类型断言、反射或类似的方法。

看看这个例子:

package main

import (
	"fmt"
)

func main() {
	slice := make([]interface{}, 3)
	slice[0] = 1
	slice[1] = "hello"
	slice[2] = true

	for _, v := range slice {
		switch v.(type) {
		case string:
			fmt.Println("我们有一个字符串")
		case int:
			fmt.Println("这是一个整数!")
			// 由于v的类型是interface{},你仍然需要进行类型断言
			fmt.Printf("它的值实际上是 %d\n", v.(int))
		default:
			fmt.Println("这是其他类型")
		}
	}
}

在这里,我们构造了一个类型为空接口的切片(任何类型都实现它),进行了类型切换,并根据结果处理值。

不幸的是,在处理未指定类型(空接口)的数组时,你将需要这样的方法(或类似的方法)。此外,除非你有一种处理任何可能类型的对象的方法,否则你可能需要为每种可能的类型编写一个case。

一种方法是使你想要存储的所有类型都实现你的某个接口,然后只通过该接口使用这些对象。这有点类似于fmt如何处理泛型参数-它只是调用任何对象的String()方法来获取其字符串表示形式。

英文:

As Go is a statically typed language, that won't be as easy as in Python. You will have to resort to type assertions, reflection or similar means.

Take a look at this example:

package main

import (
    "fmt"
)

func main() {
    slice := make([]interface{}, 3)
    slice[0] = 1
    slice[1] = "hello"
    slice[2] = true

    for _, v := range slice {
	    switch v.(type) {
	    case string:
		    fmt.Println("We have a string")
	    case int:
		    fmt.Println("That's an integer!")
		    // You still need a type assertion, as v is of type interface{}
		    fmt.Printf("Its value is actually %d\n", v.(int))
	    default:
		    fmt.Println("It's some other type")
	    }
    }
}

Here we construct a slice with the type of an empty interface (any type implements it), do a type switch and handle the value based on the result of that.

Unfortunately, you'll need this (or a similar method) anywhere where you'll be dealing with arrays of unspecified type (empty interface). Moreover, you'll probably need a case for every possible type, unless you have a way to deal with any object you could get.

One way would be to make all of the types you want to store implement some interface of yours and then only use those objects through that interface. That's kind of how fmt handles generic arguments – it simply calls String() on any object to get its string representation.

huangapple
  • 本文由 发表于 2013年8月24日 17:14:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/18416889.html
匿名

发表评论

匿名网友

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

确定