我指的是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.
我有两个问题:
非常感谢
答案 0 :(得分:6)
这并不完全具体,所以与其他回答者不同,我会选择更通用的路线。
...
) ...
这里称为“省略号”,表示该函数可以接收可变数量的参数,通常称为varargs(或var-args或其他拼写)。这称为variadic function。
这仅仅意味着,根据以下签名:
func Printf(format string, v ...interface{}) (n int, err error) {}
Printf
将期望第一个类型为string
的参数,然后是0到N个类型为interface{}
的参数。有关该类型的更多信息,请参阅下一节。
虽然提供任意数量的参数的能力看起来非常方便,而且这里没有太多细节可能会出现偏离主题的风险,但根据语言的实现情况,它会附带一些警告:
我会留意你从上面的资源中查找原因。
interface{}
)此语法位稍微特定于Go,但提示名称为interface
。
接口(或更接近Go的范例,协议)是一种定义其他对象要遵守的合同的类型。根据这篇关于Wikipedia的interfaces in computing文章(重点是粗体矿和斜体修正矿):
在面向对象语言中,**术语“接口”通常用于定义不包含数据的抽象类型,但公开定义为方法的行为。具有对应于该接口的所有方法的类被称为实现该接口。此外,一个类可以 [在某些语言中] 实现多个接口,因此可以同时使用不同的类型。
接口因此是一种类型定义;可以交换对象的任何地方(在函数或方法调用中)可以根据接口而不是特定类来定义要交换的对象的类型。这允许以后的代码使用相同的函数来交换不同的对象类型; _ [旨在] _通用且可重复使用。
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{}
会启发您。