golang语言 []interface{}和interface{}

golang语言 []interface{}

interface(接口)

interface(接口)是golang最重要的特性之一,Interface类型可以定义一组方法,但是这些不需要实现。

请注意:此处限定是一组方法,既然是方法,就不能是变量;而且是一组,表明可以有多个方法。

interface是为实现多态功能,多态是指代码可以根据类型的具体实现采取不同行为的能力。如果一个类型实现了某个接口,所有使用这个接口的地方,都可以支持这种类型的值。

Go语言里面设计最精妙的应该算interface,它让面向对象,内容组织实现非常的方便。

interface应用场景

类型转换
实现多态功能

interface{} 空接口

在Goland中有一种特殊类型:interface{} ,空接口。go中其他的类型都是没有{}的, 只有interface{}有。

interface{} 类型是没有方法的接口。由于没有 implements 关键字,所以所有类型都至少实现了 0 个方法,所以 所有类型都实现了空接口。这意味着,如果编写一个函数以 interface{} 值作为参数,那么可以为该函数提供任何值,并且,[]interface{}在golang中也可以认为是interface{}。

总结:万能类型(interface{})很神奇,就像 C 里面的 void*、 像 Java 中的 Object 类型。任何变量都可以赋值给interface{}类型的变量。
工作中,当我们使用 interface{} 作为函数形参时, 我们可以传入任何类型作为参数,因为任何类型都实现了 interface{} 接口。

[]interface{}

当我们声明 interface{} 数组的时候,事情就变的不一样了

func Foo(a []interface{
    
    }) {
    
    }

Foo([]int{
    
    1, 2, 3}) // 报错
Foo([]string{
    
    "1", "2", "3"}) // 报错

按照本身的设想,这里应该不管什么样的数组都可以作为参数传入,可是结果却恰恰相反:我们只能传入类型为 []interface{} 的元素。

既然interface{}能代表任意类型,那么interface{}的切片为什么不能代表任意类型的切片呢?

因为 []interface{} 类型变量拥有特定的内存结构。

每个 interface{} 占两个字(32 位机器一个字是 32 位,64 位机器一个字是 64 位)。其中,一个字用于存放 interface{} 真正传入的数据的类型;另一个字用于指向实际的数据。

type eface struct {
    
    
    _type *_type
    data  unsafe.Pointer
}

对于[]interface{}类型的变量来说,切片里的每个元素可以存储不同类型的变量,例如

func main() {
    
    
	var a = make([]interface{
    
    }, 0)
	a = append(a, []int{
    
    123, 456})
	a = append(a, []string{
    
    "abc", "ijk"})
	fmt.Println(a) // [[123 456] [abc ijk]]
}

长度为 n 的 []Type 切片的背后数据分配的大小为为 n * sizeof(Type) 字 长。
自然就不可以将 []int 类型作为 []interface{} 类型进行传递,只能自己写个循环将每一个 Type 都转化为 interface{}。
即使切片里存的数据都是某个特定的类型,也不能通过类型断定来强制转换,因为底层的数据存储结构不同

func main() {
    
    
	a := method()
	_, ok := a.([]int)
	fmt.Println(ok) // false
}

func method() interface{
    
    } {
    
    
	var a = make([]interface{
    
    }, 0)
	a = append(a, []int{
    
    123, 456})
	a = append(a, []int{
    
    789, 111})
	return a
}

Each interface{} takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type []interface{} is backed by a chunk of data that is N*2 words long.

This is different than the chunk of data backing a slice with type []MyType and the same length. Its chunk of data will be N*sizeof(MyType) words long.

The result is that you cannot quickly assign something of type []MyType to something of type []interface{}; the data behind them just look different.

每个接口{}占用两个单词(一个单词,用于包含的类型,另一个单词包含数据或指针的单词)。结果,具有长度n和类型[]接口{}的切片是由一块n*2个单词长的数据支持。

这与以[] mytype类型和相同长度的类型备份的数据片段不同。它的数据很多将是n*sizeof(mytype)单词。

结果是您无法快速将某些类型[] mytype分配给类型[] interface {}的东西;它们背后的数据看起来不同。

总结:interface slice 与 万能类型 empty interface 是不一样的,可以直接将任何类型的值传给万能类型,但是不能将任何类型的 slice 直接传给 interface slice,因为 interface slice 并不是万能类型,只是里面装的东西是万能类型,所以反过来你也不能直接将 interface slice 强制转换成特定类型的 slice。

golang中为什么[]string 不能直接转换[]interface{}

golang中为什么[]string 不能直接转换[]interface{}
原文链接

工作中遇到问题整理

interface{} 类型赋值其他变量报错 cannot use variable (type interface {}) as type int in assignment: need type assertion

package main

import "fmt"

func main() {
    
    
	var tmp interface{
    
    }
	var i int
	tmp = 1
	i = tmp
	fmt.Println(i)
}

报错的代码行是 i = tmp 那行。

可见,interface{} 类型可以被任何类型赋值,但是 interface{} 不可以直接给其他类型赋值。

解决方法

//i = tmp
i = tmp.(int)

参考

InterfaceSlice
参考URL: https://github.com/golang/go/wiki/InterfaceSlice
interface{} 与 []interface{}
参考URL: https://blog.csdn.net/lwldcr/article/details/77370948
Golang 的 []interface{} 类型
参考URL: https://www.cnblogs.com/xhyccc/p/15807778.html
理解Golang中的[]interface{}和interface{}
参考URL: https://blog.csdn.net/qq_39220627/article/details/119191249

猜你喜欢

转载自blog.csdn.net/inthat/article/details/127170455