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

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

// 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 编译器上工作。

例如:

interface IFoo {

void Say();

};

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

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

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

例如:

type IFoo interface {

Say()

}

type FooImplement struct {

}

func (*FooImplement) Say() {

fmt.Println("你好!")

}

func main() {

var foo IFoo

foo = &FooImplement{}

foo.Say()

}

 举一反三:

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 指令拆箱的过程。

例如:

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)会发生一些很有意思的参数转发问题。

举个例子:

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到线程栈空间之中。

public void PrintNumbers(params object[] numbers)

{

foreach (var number in numbers)

{

Console.WriteLine(number);

}

}

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

func implement_print_args(a ...any) {

fmt.Println(a...)

}

func forward_print_args(a ...any) {

implement_print_args(a...)

}

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

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。