EricJJ' Blog

Go 初学者问题总结

2017-09-12

  1. 1. make 和 new 的区别
  2. 2. Go语言参数传递是传值还是传引用
  3. 3. go怎么从源码编译到二进制文件
  4. 4. 其他

make 和 new 的区别

  • new是内建函数,函数原型为
func new(Type) *Type

官方文档描述为:

The new build-in functionallocates memory(仅仅分配空间). The first argument is a type, not a value, and the value returned is a pointer to a newly allocated zero value of that type.

内置函数new分配空间。传递给new函数的是一个 类型 ,不是一个值。返回值是 指向这个新分配的零值的 指针

  • make 也是内建函数,你可以从 http://golang.org/pkg/builtin/#make 看到它, 它的函数原型 比 new 多了一个(长度)参数,返回值也不同。
    函数原型是:
func make(Type, size IntegerType) Type

第一个参数是一个类型,第二个参数是长度
返回值是一个类型
官方描述为:

The make built-in function allocates and initializes an object(分配空间 + 初始化) of type slice, map or chan(only). Like new , the first arguement is a type, not a value. Unlike new, make’s return type is the same as the type of its argument, not a pointer to it. The specification of the result depends on the type.

内建函数 make 分配并且初始化 一个 slice, 或者 map 或者 chan 对象。 并且只能是这三种对象。 和 new 一样,第一个参数是 类型,不是一个值。 但是make 的返回值就是这个类型(即使一个引用类型),而不是指针。 具体的返回值,依赖具体传入的类型。

Slice : 第二个参数 size 指定了它的长度,此时它的容量和长度相同。
你可以传入第三个参数 来指定不同的容量值,但是必须不能比长度值小。
比如: make([]int, 0, 10)

Map: 根据size 大小来初始化分配内存,不过分配后的 map 长度为0。 如果 size 被忽略了,那么会在初始化分配内存的时候 分配一个小尺寸的内存。

Channel: 管道缓冲区依据缓冲区容量被初始化。如果容量为 0 或者被 忽略,管道是没有缓冲区的。

var p *[]int = new([]int)
var v []int = make([]int, 10)

上述第一条语句 使用 new() 函数为 切片结构分配内存,*p == nil (这意味着什么? 意味着没有对Slice结构进行初始化), 但是在实际中这种用法很少使用。
第二条语句使用 make() 函数创建了一个有10个元素的 Slice对象。

Go语言参数传递是传值还是传引用

最终我们可以确认的是Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。

是否可以修改原内容数据,和传值、传引用没有必然的关系。在C++中,传引用肯定是可以修改原内容数据的,在Go语言里,虽然只有传值,但是我们也可以修改原内容数据,因为参数是引用类型。

这里也要记住,引用类型和传引用是两个概念。

再记住,Go里只有传值(值传递)。

https://www.flysnow.org/2018/02/24/golang-function-parameters-passed-by-value.html

go怎么从源码编译到二进制文件

go build -n hello.go

-n 不执行地打印流程中用到的命令

创建临时目录,mkdir -p $WORK/b001/;
查找依赖信息,cat >$WORK/b001/importcfg << …;
执行源代码编译,/usr/local/go/pkg/tool/darwin_amd64/compile …;
收集链接库文件,cat >$WORK/b001/importcfg.link << …;
生成可执行文件,/usr/local/go/pkg/tool/darwin_amd64/link -o …;
移动可执行文件,mv $WORK/b001/exe/a.out hello;

其他

1. 如果要修改 receiver, 必须将其设为一个指针, 指针是指保存了另一个值得内存地址的变量, 原因之一是为了效率, 比如我们有一个很大的值, 传入一个指向该值所在内存地址的指针会比传入该值本身更廉价得多;

2. channel map slice 等数据结构必须通过 make 函数创建, 而 make 函数返回的是该类型的一个引用, 引用的行为和指针非常类似, 当把它们传入函数的时候, 函数内对该引用所做的任何改变都会作用到该引用所指向的原始数据;

3. 通常情况下 Go 语言的变量持有相应的值, 可以将一个变量想象成它所持有的值来使用,期中有些例外是对于通道,函数,方法,映射,以及切片的引用变量, 他们持有的都是引用, 也即保存指针的变量

4. 与 C 和 C++ 不同, Go语言的数组是按值传递的, 因此传递一个大数组的带价非常大, 幸运的是, 在 GO 语言中数组不常用到,因为我们可以用切片来代替, 与字符串不同, 修改切片不会导致写时复制的负担, 因为不同于字符串的是, 切片是可变的

5. new 是返回指针, make 返回引用,用于 channel, map,slice;