golang any 之中的类型及 interface 接口

在 golang 之中 any 类型,从字面意思上看是任意类型,这很类似我们在 C#、C++ 之中的任意指针类型 void*(原生),C# 之中诡异的 object。

any 是一个接口类型,其语法声明为:

Go 复制代码
// any is an alias for interface{} and is equivalent to interface{} in all ways.

type any = interface{}

即 interface{} 等于 any,这是一种类似 C++ 之中语法为:

using 别名 = 类型;

别名定义方式,C# 这块只允许为命名空间定义别名,就像在 C++ 使用 namespace 别名 = 命名空间; 类似这样子。

Golang 与 C/C++、C# 这样的语言是不同的,在 VC++ 之中微软提供了 __interface 关键字,将 C/C++ 混乱不堪的定义 Abstract class 为强行理解为 interface 行为给取缔,但可惜的是:它只被允许在 Microsoft VC++ 、CL 编译器上工作。

例如:

cpp 复制代码
interface IFoo {
    void Say();
};

在 C++ 及 C# 之中,接口必须在具象类(Representational class)之中被显示派生才可以,它是基于对于 __vfptr 类虚函数表重写实现的。

当然与 Golang 相同,接口函数必须被具象类按照 "Function signature 函数签名" 实现才可以,但不同的是,Golang 之中不需要在 struct 之中声明派生具体的接口类型。

在 Golang 之中类型是否可以 "Covariations 协变" 为某个接口类型,只需要该类型实现,欲被协变的接口所需要的成员。

例如:

Go 复制代码
type IFoo interface {
	Say()
}

type FooImplement struct {
}

func (*FooImplement) Say() {
	fmt.Println("你好!")
}

func main() {
	var foo IFoo
	foo = &FooImplement{}

	foo.Say()
}

举一反三:

cpp 复制代码
type IFoo interface{}

type FooImplement struct{}

func (*FooImplement) Say() {
	fmt.Println("你好!")
}

func test_foo(foo IFoo) {

}

func test_any(v any) {
	test_foo(v)
}

func main() {
	foo := &FooImplement{}
	test_any(foo)
}

如上所示:

所以:当用户 interface 被定义为空集时,它与 interface {} 或者说 any 类型(别名)是等价的,可以无障碍的相互传递。

注意:

Golang 接口只可定义接口函数,但C#、VB.NET、C++ .NET 可以允许定义,如接口成员属性、成员事件等。

当 interface 接口类型想要 "Contravariants 逆变" 为具体类型的时候,这个过程人们可以想象为一种 unbox 指令拆箱的过程。

例如:

cpp 复制代码
type IFoo interface {
	Say()
}

type FooImplement struct{}

func (*FooImplement) Say() {
	fmt.Println("你好!")
}

func test_foo(foo IFoo) {
	f, ok := foo.(*FooImplement)
	if ok {
		f.Say()
		fmt.Println("拆箱成功!")
	} else {
		fmt.Println("拆箱失败!")
	}
}

func main() {
	foo := &FooImplement{}
	test_foo(foo)
}

在 Golang 之中 any 类型是一个很奇怪的东西,如果我们声明某个函数为 ... any 可变参数类型(any)会发生一些很有意思的参数转发问题。

举个例子:

Go 复制代码
func implement_print_args(a ...any) {
	fmt.Println(a...)
}

func forward_print_args(a ...string) {
	implement_print_args(a...)
}

上述代码是无法编译通过的,从人类易于理解的角度来说,any 类型的可变参数,应该是可以接受任何类型的,这也应当包含 string 类型。

但奇怪的是 forward_print_args 函数,根本无法把自己的可变字符串类型参数 a,转发给 implement_print_args 函数。

这是因为,在 Golang 语言之中,any 的确可以等于任何类型,但在不等于它不存在限制,另外在 Golang 之中的可变参数是像 C# 语言之中使用一个 object[] 数组来模拟的可变参数。

人们稍需注意一点,Golang 并非是像 C/C++ 语言之中,真正意义上的可变参数,即根据函数调用协议(如 __cdecl、__stdcall、__fastcall、__thiscall、__pascal)及平台来决定那些参数压入到寄存器,如RDX、RCX、那些参数PUSH到线程栈空间之中。

Go 复制代码
public void PrintNumbers(params object[] numbers)
{
    foreach (var number in numbers)
    {
        Console.WriteLine(number);
    }
}

所以在 golang 之中,如果人们需要转发类型为 ... any 的可变参数列表,应当:

Go 复制代码
func implement_print_args(a ...any) {
	fmt.Println(a...)
}

func forward_print_args(a ...any) {
	implement_print_args(a...)
}

但这并不仅仅是 any,定义任何类型的可变参数,都应当按照上述形式来声明函数及参数签名。

相关推荐
无聊写博客10 分钟前
JDK、JRE、JVM的区别
java·开发语言·jvm
黑不溜秋的11 分钟前
C++ 编程指南04 - 尽量编写静态类型安全的程序
开发语言·c++·安全
j1780505690619 分钟前
C#学习笔记——窗口停靠控件WeifenLuo.WinFormsUI.Docking使用-腾讯云开发者社区-腾讯云
开发语言·c#
搬砖的小码农_Sky22 分钟前
C语言:字符串
c语言·开发语言
大熊程序猿23 分钟前
python Flask指定IP和端口
开发语言·python·flask
YONG823_API30 分钟前
1688商品数据采集API的测试对接步骤分享(提供免费测试key)
开发语言·数据库·爬虫·python·数据挖掘
恬淡虚无真气从之41 分钟前
go interface(接口)使用
开发语言·后端·golang
她说—技术支持1 小时前
MATLAB 2024a安装包下载及安装教程
开发语言·matlab
程序猿毕设源码分享网1 小时前
基于springboot停车场管理系统源码和论文
数据库·spring boot·后端
努力学习的饼干1 小时前
C++模版特化和偏特化
开发语言·c++