Go语言中,fmt.Println()和println()有何不同?

179
如下所示,无论是 fmt.Println() 还是 println() 在 Go 中都会输出同样的结果:Hello world! 但是:它们有什么不同之处呢?
代码片段 1 使用 fmt 包;
package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello world!")
}

没有使用fmt包的代码片段2;

package main

func main() {
    println("Hello world!")
}
5个回答

172

println是一种内置函数(集成到运行时中),可能会被移除,而fmt包在标准库中,将持续存在。详见规范

对于语言开发人员来说,拥有一个没有依赖关系的println很方便,但正确的做法是使用fmt包或类似的东西(例如log)。

正如你可以在实现中看到的print(ln)函数并不设计用于支持不同的输出模式,主要用于调试工具。


148

针对Nemo的回答进行补充:

println是该语言内置的一个函数。它在规范的引导部分中。从链接中可以看到:

当前的实现提供了几个内置函数,在引导过程中非常有用。这些函数为了完整性而被记录,但不能保证一定会留在语言中。它们不返回结果。

Function   Behavior

print      prints all arguments; formatting of arguments is implementation-specific
println    like print but prints spaces between arguments and a newline at the end
因此,它们对于开发人员很有用,因为它们没有依赖项(已构建到编译器中),但在生产代码中则不然。值得注意的是,printprintln 将内容报告给stderr而不是stdout
然而,由fmt提供的系列函数专为生产代码而设计。它们可按预期报告到stdout,除非另有指定。它们更加灵活(fmt.Fprint*可以报告到任何io.Writer,例如os.Stdoutos.Stderr或甚至是net.Conn类型),并且不具体实现。
大多数负责输出的包都将fmt作为依赖项,例如log。如果您的程序将在生产环境中输出任何内容,则fmt很可能是您想要的包。

“but not in production code” 的意思是仅限于开发环境,不应出现在生产环境的代码中。当我运行 go build 命令时,生成的二进制文件仍然会包含 println 输出的文本信息。 - Minh Nghĩa
这只是意味着它不应该在“重要”的代码中使用。生产代码是指用于某种公司或政府机构使用的更大型项目或产品的代码。换句话说,对于家庭作业来说没问题,但对于一名得到报酬从事工作的软件工程师来说就不行了。 - Mike Williamson

7
我看到这里的区别:

rangeOverIntsAndStrings(1, 5)

对整数和字符串的范围进行操作

func rangeOverIntsAndStrings(args ...interface{}) {
    for _, v := range args {
        println(v)
    }
}

// 输出

(0x108f060,0x10c5358)
(0x108f060,0x10c5360)

对比

func rangeOverIntsAndStrings(args ...interface{}) {
    for _, v := range args {
        fmt.Println(v)
    }
}

抱歉,我只能使用英语进行翻译。
1
5

-1
有趣的例子:
➜  netpoll git:(develop) ✗ cat test.go
package main

import "fmt"

func main() {
        a := new(struct{})
        b := new(struct{})
        println(a, b, a == b)

        c := new(struct{})
        d := new(struct{})
        fmt.Printf("%v %v %v\n", c, d, c == d)
}
➜  netpoll git:(develop) ✗ go run test.go       
0xc000074f47 0xc000074f47 false
&{} &{} true
➜  netpoll git:(develop) ✗ go run -gcflags="-m" test.go
# command-line-arguments
./test.go:12:12: inlining call to fmt.Printf
./test.go:6:10: new(struct {}) does not escape
./test.go:7:10: new(struct {}) does not escape
./test.go:10:10: new(struct {}) escapes to heap
./test.go:11:10: new(struct {}) escapes to heap
./test.go:12:35: c == d escapes to heap
./test.go:12:12: []interface {} literal does not escape
<autogenerated>:1: .this does not escape
0xc000074f47 0xc000074f47 false
&{} &{} true

printlnfmt.Printf之间有一些不同。


3
дёєд»Ђд№€дЅ жІЎжњ‰е°†printlnе’Њfmt.Printlnиї›иЎЊжЇ”иѕѓе‘ўпјџ - Xplouder

-2
关于区别,this 是一个例子。 println() 打印指向函数 test 的地址指针。 fmt.Println() 打印函数的地址。

17
我不明白你想表达什么意思。 - Pierrot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接