什么是... interface {}作为参数

时间:2013-09-05 06:33:45

标签: go

我指的是http://golang.org/pkg/log/

上func Printf的来源
func Printf(format string, v ...interface{})
Printf calls Output to print to the standard logger. Arguments are handled in the manner of fmt.Printf.

我有两个问题:

  1. 什么是'...'?
  2. 接口{}是什么意思?
  3. 非常感谢

3 个答案:

答案 0 :(得分:6)

这并不完全具体,所以与其他回答者不同,我会选择更通用的路线。

On Variable Arguments(...

...这里称为“省略号”,表示该函数可以接收可变数量的参数,通常称为varargs(或var-args或其他拼写)。这称为variadic function

这仅仅意味着,根据以下签名:

func Printf(format string, v ...interface{}) (n int, err error) {}

Printf将期望第一个类型为string的参数,然后是0到N个类型为interface{}的参数。有关该类型的更多信息,请参阅下一节。

虽然提供任意数量的参数的能力看起来非常方便,而且这里没有太多细节可能会出现偏离主题的风险,但根据语言的实现情况,它会附带一些警告:

  • 增加内存消耗,
  • 可读性下降,
  • 降低代码安全性。

我会留意你从上面的资源中查找原因。

在空接口(interface{}

此语法位稍微特定于Go,但提示名称为interface

接口(或更接近Go的范例,协议)是一种定义其他对象要遵守的合同的类型。根据这篇关于Wikipediainterfaces in computing文章(重点是粗体矿和斜体修正矿):

  

在面向对象语言中,**术语“接口”通常用于定义不包含数据的抽象类型,但公开定义为方法的行为。具有对应于该接口的所有方法的类被称为实现该接口。此外,一个类可以 [在某些语言中] 实现多个接口,因此可以同时使用不同的类型。

     

接口因此是一种类型定义;可以交换对象的任何地方(在函数或方法调用中)可以根据接口而不是特定类来定义要交换的对象的类型。这允许以后的代码使用相同的函数来交换不同的对象类型; _ [旨在] _通用且可重复使用。

现在回到Go的空接口

Go是一种强类型语言,有几种内置类型,包括Interface Types,它们在当前(1.1)语言规范中描述为gollows:

  

接口类型指定称为其接口的方法集。接口类型的变量可以使用方法集存储任何类型的值,该方法集是接口的任何超集。据说这种类型实现了界面。

再说一遍,你会看到你在Printf的签名中看到的构造interface{}(强调我的大胆):

  

类型实现包含其方法的任何子集的任何接口,因此可以实现几个不同的接口。例如,所有类型都实现空接口

interface{}

这基本上意味着任何类型都可以表示为“空接口”,因此Printf可以接受这些变量的任何类型的变量。


与其他语言的快速比较

历史上,名称printf来自C函数和同名二进制文件printf,意思是“打印格式化”,尽管早期语言中有可变参数打印函数,并且可变函数用于许多其他场景。但是,printf通常被认为是此类用法的主要示例。它在C中的签名是:

int printf(const char *format, ...);

由于它们的实用性,varargs和printf熟悉的面孔出现在大多数语言中......

在Java中,printf以多种形式存在,特别是来自PrintStream类:

public PrintStream printf(String format, Object... args)

其他一些语言并不打扰指定变量参数并使其隐式,例如在JavaScript中,函数中的arguments特殊变量允许访问传递给函数的任何参数,无论它们是否与原型匹配或不

console.log()方法将是一个类似于printf的示例,为了清晰起见,扩展了以下伪签名(但实际上只是使用arguments):

console.log(obj1 [, obj2, ..., objN);
console.log(msg [, subst1, ..., substN);

答案 1 :(得分:4)

文档直接回答您的问题。这是链接和相关部分:

http://golang.org/doc/effective_go.html

Printf的签名使用类型... interface {}作为其最终参数,以指定在格式之后可以出现任意数量的参数(任意类型)。

func Printf(format string, v ...interface{}) (n int, err error) {

在函数Printf中,v的作用类似于[] interface {}类型的变量,但是如果它被传递给另一个可变参数函数,它就像一个常规的参数列表。这是我们上面使用的函数log.Println的实现。它将其参数直接传递给fmt.Sprintln以进行实际格式化。

// Println prints to the standard logger in the manner of fmt.Println.
func Println(v ...interface{}) {
    std.Output(2, fmt.Sprintln(v...))  // Output takes parameters (int, string)
}

我们在对Sprintln的嵌套调用中写入...后告诉编译器将v视为参数列表;否则它只会将v作为单个切片参数传递。

答案 2 :(得分:3)

Go文档非常好,语言规范写得非常好,并且可以理解。为什么不看看?

http://golang.org/ref/spec#Function_types

http://golang.org/ref/spec#Passing_arguments_to_..._parameters

http://golang.org/ref/spec#Interface_types

浏览器中的Ctrl-F并查找...interface{}会启发您。