go 变量声明初始化、new、make

栏目: Go · 发布时间: 5年前

内容简介:title: go 变量声明初始化、new、makedate: 2019-01-04tags:

title: go 变量声明初始化、new、make

date: 2019-01-04

tags:

- golang

- 变量声明和初始化

- new

- make

categories:

- golang学习

变量的声明和初始化

实验一

起源于大远问,下面的代码会输出什么?

type Person struct {
    name string
    age int
}

func main() {
    var p Person
    fmt.Println(p.age)
}

按照我之前的理解,报错。因为p只是声明了,并没有初始化。

但是打印出来却是 0

说明Person对象确实初始化了。

实验二

func main() {
    var p *Person
    fmt.Println(p) //<nil>
    fmt.Println(p.age) //panic: runtime error: invalid memory address or nil pointer dereference
}

声明一个变量,初始化的内容只跟变量的类型相关

声明了一个 *Person 类型的指针p,说明 p 初始化的内容就是指针的默认值,那就是 nil 了。

打印p.age出错,证明了Person并没有初始化,当然是空指针错误了。

我们可以画图说明下两者的关系

go 变量声明初始化、new、make

微信图片_20190106203742.jpg

总结

  1. nil 只能赋值给指针类型的变量,实际上nil就是是指针类型变量的零值。值类型的变量有各自的零值 比如 int 是 0 string 是 ""
  2. 变量的声明,无论是值类型还是指针类型的变量,声明之后,变量都会占有一块内存,并且被初始化为一个零值,被初始化的内容只跟变量的类型有关(注意:Post,跟*Post是两种类型
    var i int // 值类型 因此 i 是 0
    var p Person // 值类型 因此 p.title 是“” p.num 是 0
    var po Person // 初始化的不是Post类型,而是 Post类型,即指针类型,因此p是nil p.title 会报错

make和new

new 和 make 都可以用来分配空间,初始化类型。他们和上面有什么关系吗?

new(T) 返回的是 T 的指针

func main() {
    a := new(int)
    *a = 3
    fmt.Printf("%T,%p,%p,%v\n",a,&a,a,a) // *int,0xc000006028,0xc00000a0a8,0xc00000a0a8

    b := new(Person)
    fmt.Printf("%T,%p,%p,%v\n",b,&b,b,b.age) // *main.Person,0xc000006038,0xc000004460,0

    c := new(Person)
    c = &Person{"xuxiaofeng",26}
    fmt.Printf("%T,%p,%p,%v\n",c,&c,c,c.age) // *main.Person,0xc000006040,0xc0000044a0,26
}

画图表示一下

go 变量声明初始化、new、make

微信图片_20190106203742.jpg

第三段中,new就相当于下面这两句话

var c *Person
c = &Person{"xuxiaofeng",26}

如果我们 new(*Person) 呢,道理还是同样的道理,只是多了一层指针,指针的指针,容易绕晕。

func main() {
    a := new(*Person)
    fmt.Printf("%T.%p,%p\n",a,&a,a)  // **main.Person.0xc000006028,0xc000006030
    //a = Person{}  // error
    //a = &Person{}  // error
    //*a = Person{}  //error
    *a = &Person{"xuxiaofeng",16}
    fmt.Printf("%T.%p,%p\n",*a,&(*a),*a)  // *main.Person.0xc000006030,0xc000004460
    fmt.Println((**a).age)
}

画图表示一下

go 变量声明初始化、new、make

微信图片_20190106203742.jpg

make 只能用于 slice,map,channel

make基本使用就不做介绍了,只要注意只能是slice,map,channel,这三种类型就可以了。这三种类型都是引用类型

new slice

我们能否 new([]int) new一个slice呢?

func main() {
    a := new([]int)
    //a[0] = 1  //(type *[]int does not support indexing)
    //(*a)[0] = 2  // error: index out of range
    fmt.Println(len(*a),cap(*a)) //0 0
    *a = append(*a,1)
    fmt.Printf("%T\n",a)  //*[]int
    fmt.Println((*a)[0])  //1
}

我们看也是可以的,只是给我们返回了长度和容量都是0的slice,而append之后,slice的底层数据已经不是原来的数组了。

new map

func main() {
    a := new(map[string]int)
    (*a)["xuxaiofeng"] =26  //panic: assignment to entry in nil map
    fmt.Println(*a)

}

new chan

func main() {
    a := new(chan int)
    go func() {
        (*a) <- 2
    }()
    t := <-*a
    fmt.Println(t)
}
//fatal error: all goroutines are asleep - deadlock!
//goroutine 1 [chan receive (nil chan)]:

说明我们创建的chan就是一个nil,还没有初始化,从一个nil中读数据,程序当然会deadlock

总结

new(T) 返回 T 的指针 *T 并指向 T 的零值。

make(T) 返回的初始化的 T,只能用于 slice,map,channel。

p.name 和*p.name

func main() {
    p := new(Person)
    //p = Person{"xuxiaofeng",26} //cannot use Person literal (type Person) as type *Person in assignment
    p.name = "xuxiaofeng"
    fmt.Println(p)
}

p是*Person,是Person的指针,所以不能直接复制,要想复制也要这样 p = &Person{"xuxiaofeng",26} ,但是为什么调用字段的时候就可以 p.name = "xuxiaofeng"

如果 x 是可寻址的,&x 的 filed 集合包含 m,x.m 和 (&x).m 是等同的,go 自动做转换,也就是 p.name和 (*p).name调用是等价的,go 在下面自动做了转换。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web标准和SEO应用实践

Web标准和SEO应用实践

Aarron Walter / 李清 / 机械工业出版社 / 2008 / 36.00元

本书是关于搜索引擎优化和易发现性的技术指南。. 本书介绍Web标准、可访问性以及Ajax、API、Flash和微格式等内容,包括标记策略、服务器端策略、内容策略、建构易发现的博客、在网站内添加搜索、防止易发现性障碍、用邮件列表挽回流量、将易发现性付诸实践。 本书适合网站开发者与SEO技术业余爱好者等参考。 这不是为营销专家写的一本SEO的书。 针对那些想要找到网站的目标用户......一起来看看 《Web标准和SEO应用实践》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换