我指的是http://golang.org/pkg/log/上的Func Printf的来源

我有两个问题:

  • 是什么 '...' ?
  • ... interface {}是什么意思?
  • 非常感谢你


    这并不完全是特定的,因此与其他答复者不同,我将走更一般的路线。

    关于可变参数(...)

    此处的...称为"省略号",表示函数可以接收可变数量的参数,通常称为varargs(或var-args或其他拼写形式)。这称为可变函数。

    它仅表示根据以下签名:

    Printf将期望第一个类型为string的参数,然后在0到N个类型为interface{}的参数之间。下一节将详细介绍该类型。

    尽管提供任何数量的参数的功能似乎非常方便,并且在这里不必过多讨论细节,否则可能会出现偏离主题的风险,但根据语言的实现,它会带来一些警告:

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

    我将由您自己决定从以上资源中查找原因。

    在空接口(interface{})上

    该语法位更特定于Go,但是提示的名称为:interface

    接口(或更接近Go的范例,一种协议)是一种类型,它定义了其他对象要遵守的协定。根据有关计算接口的Wikipedia文章(粗体字强调和斜体字修改):

    In object-oriented languages, **the term"interface" is often used to define an abstract type that contains no data, but exposes behaviors defined as methods. A class having all the methods corresponding to that interface is said to implement that interface. Furthermore, a class can [in some languages]) implement multiple interfaces, and hence can be of different types at the same time.

    An interface is hence a type definition; anywhere an object can be exchanged (in a function or method call) the type of the object to be exchanged can be defined in terms of an interface instead of a specific class. This allows later code to use the same function exchanging different object types; _[aiming to be]_ generic and reusable.

    现在回到Go的空白界面

    Go是一种强类型语言,具有多种内置类型,包括接口类型,它们在当前的(1.1)语言规范中被描述为gollows:

    An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface.

    进一步,将介绍在Printf的签名interface{}中看到的构造(以黑体字强调):

    A type implements any interface comprising any subset of its methods and may therefore implement several distinct interfaces. For instance, all types implement the empty interface:

    1
    interface{}

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


    与其他语言的快速比较

    从历史上看,名称Printf来自C函数,并且来自相同名称的二进制文件,Printf表示"打印格式",尽管早期语言中有可变参数打印功能,可变参数功能还用于许多其他情况。但是,Printf通常被认为是这种用法的主要示例。它在C中的签名是:

    由于其实用性,varargs和Printf熟悉的面孔在大多数语言中都会显示出来...

    在Java中,Printf存在多种形式,尤其是PrintStream类中的形式:

    其他一些语言不会麻烦地指定变量参数并将其隐式化,例如在JavaScript中,函数内的arguments特殊变量允许访问传递给函数的任何参数,无论它们是否与原型匹配。

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


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

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

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

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

    我们在对Sprintln的嵌套调用中在v之后编写...,以告诉编译器将v视为参数列表。否则,它将仅将v作为单个slice参数传递。


    Go文档非常好,Language规范确实写得很好并且易于理解。为什么不看看?

    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{}将会启发您。