在Go语言中,如何读取一个`[]interface{}`类型的切片呢?

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

How to read an slice of like []interface{} in Go?

问题

我有这样的代码:

a := []interface{}{}
b := []interface{}{}
type S struct {
  text string
}


s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a := append(a, b)

a

现在我想读取a的元素,或者元素的元素...但是怎么做呢?

英文:

I have something like this:

a := []interface{}{}
b := []interface{}{}
type S struct {
  text string
}


s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a := append(a, b)

a

And now I want to read elements of a, or elements of elements.. but how?

答案1

得分: 4

你想要的是称为类型断言的东西。http://golang.org/ref/spec#Type_assertions

该页面上的简单示例是:

var x interface{} = 7  // x 的动态类型是 int,值为 7
i := x.(int)           // i 的类型是 int,值为 7

另一个需要注意的是,类型断言会返回一个名为 ok 的值,如果断言成功,则为 true。以下是你的情况的一个简单代码示例:

a := []interface{}{}
b := []interface{}{}
type S struct {
  text string
}


s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)

assertedS, ok := a[0].(S)
if !ok { // 如果实际上不是 S 类型的值,那么就有问题
    // 错误处理
}

fmt.Println(assertedS) // 应该显示与打印 s 相同的内容

assertedB, ok := a[1].([]interface{})
if !ok {
    //...
}

assertedT, ok := assertedB[0].(S)
if !ok {
    //...
}

fmt.Println(assertedT) // 应该显示与打印 t 相同的内容

如果事先不知道列表元素的类型,可以遍历它并使用 "类型开关"。http://golang.org/ref/spec#Switch_statements

switch x.(type) {
    // cases
}

这允许你根据存储的 interface{} 的实际类型执行条件行为。

例如,你可以使用以下代码:

func ExtractSlice(a []interface{}) {
  for _, x := range a {
    switch i := x.(type) {
    case S:
        fmt.Println(i)
    case []interface{}:
        ExtractSlice(i) // 递归地解包 b,一旦在 a 中找到它
    }
  }
}
英文:

What you want is called a type assertion. http://golang.org/ref/spec#Type_assertions

The simple example on that page is:

var x interface{} = 7  // x has dynamic type int and value 7
i := x.(int)           // i has type int and value 7`

The other thing to note is that a type assertion returns a value called ok that is true if the assertion is successful. Here's a simple code example for your case:

a := []interface{}{}
b := []interface{}{}
type S struct {
  text string
}


s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)

assertedS,ok := a[0].(S)
if !ok { // If this is, in fact, not a value of type S, something is wrong
    // error handling
}

fmt.Println(assertedS) // Should show you the same thing as printing s

assertedB,ok := a[1].([]interface{})
if !ok {
    //...
}

assertedT,ok := assertedB[0].(S)
if !ok {
    //...
}

fmt.Println(assertedT) // Should show you the same thing as printing t

If you don't know ahead of time which list element is what, you can iterate through it and use the "type switch". http://golang.org/ref/spec#Switch_statements

switch x.(type) {
    // cases
}

Which allows you to perform conditional behavior based on what type the stored interface{} really is.

For instance, you might use

func ExtractSlice(a []interface{}) {
  for _,x := range a {
    switch i := x.(type) {
    case S:
        fmt.Println(i)
    case []interface{}:
        ExtractSlice(i) // Recursively unpacks b once it's found within a
    }
  }
}

答案2

得分: 2

你是指这个吗?

a := []interface{}{}
b := []interface{}{}
type S struct {
    text string
}
s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)
for _, v := range a {
    switch v.(type) {
    case S:
        fmt.Println("S", v)
    default:
        fmt.Println("Slice", v)
    }
}
英文:

Do you mean this?

a := []interface{}{}
b := []interface{}{}
type S struct {
    text string
}
s := S{"string"}
t := S{"string"}
a = append(a, s)
b = append(b, t)
a = append(a, b)
for _, v := range a {
    switch v.(type) {
    case S:
        fmt.Println("S", v)
    default:
        fmt.Println("Slice", v)
    }
}

答案3

得分: 0

这是一个可能有帮助的代码示例:

package main

import "fmt"

func main() {
    a := []interface{}{}
    b := []interface{}{}
    type S struct {
        text string
    }

    s := S{"string s"}
    t := S{"string t"}
    a = append(a, s)
    b = append(b, t)
    a = append(a, b)

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

但请注意,你将ab定义为接口的切片。这意味着,当你执行a = append(a, b)时,你将b切片放在a切片中现有的字符串之后,因此当你对a进行range循环时,你会得到:

{string s} // 字符串的接口
[{string t}] // 字符串接口的切片
英文:

This code example may help:

package main

import "fmt"

func main() {
	a := []interface{}{}
	b := []interface{}{}
	type S struct {
		text string
	}

	s := S{"string s"}
	t := S{"string t"}
	a = append(a, s)
	b = append(b, t)
	a = append(a, b)

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

but be aware that you've defined a and b as slices of interfaces. This means, that when you do a = append(a, b) you're putting the b slice after the existing a string in the a slice, and therefore when you range over a you get:

>{string s} //interface of string
[{string t}] //slice of interface of string

huangapple
  • 本文由 发表于 2013年12月16日 20:49:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/20611367.html
匿名

发表评论

匿名网友

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

确定