zoukankan      html  css  js  c++  java
  • go语言值类型与引用类型理解,new与make的区别

    值类型与引用类型:

    在理解概念之前可以先去了解一下堆栈的知识。值类型 变量存储在栈,引用类型变量存储在堆;

    定义值类型和引用类型变量时,值类型会默认分配内存,引用类型需要new或者make手动分配内存。

    所有像 int 、float、bool和string等这些值类型,使用这些值类型的变量直接指向存在内存中的值。

    当使用等于号=将一个变量的值赋值给另外一个变量时,比如 j=i 实际上是在内存中将i的值进行拷贝;如下图

    4.4.2_fig4.2

    一个引用类型的变量 r1 存储的是r1的值所在的内存地址或者内存地址第一个字所在的位置,这个内存地址称之为指针,

    同一个引用类型的指针指向的多个字可以是在连续的内存地址中,也可以将这些字分散存放在内存中,每个字都指示下一个字所在的内存地址。

    当使用赋值语句 r2=r1 或者r3 = r1时,实际上引用(地址)被复制,如果r1所指向的值被改变了,那么对应这个值所有引用都会指向被修改后的内容,即r2和r3也随着改变。

    new与make区别:

    go语言中函数new与make的使用和区别,关于Go语言中new和make是内建的两个函数,主要用来创建分配类型内存。在我们定义生成变量的时候,可能会觉得有点迷惑,其实他们的规则很简单,下面我们就通过一些示例说明他们的区别和使用,话不多说了,来一起看看详细的介绍吧。

    变量的声明

    var i int
    var s string

    变量的声明我们可以通过var关键字,然后就可以在程序中使用。当我们不指定变量的默认值时,这些变量的默认值是他们的零值,比如int类型的零值是0,string类型的零值是"",引用类型的零值是nil。

    对于例子中的两种类型的声明,我们可以直接使用,对其进行赋值输出。但是如果我们换成引用类型呢?

    package main
    import (
     "fmt"
    )
    func main() {
     var i *int
     *i=10
     fmt.Println(*i)
    }

    这个例子会打印出什么?0还是10?。以上全错,运行的时候会painc,原因如下:

    panic: runtime error: invalid memory address or nil pointer dereference

    从这个提示中可以看出,对于引用类型的变量,我们不光要声明它,还要为它分配内容空间,否则我们的值放在哪里去呢?这就是上面错误提示的原因。

    对于值类型的声明不需要,是因为已经默认帮我们分配好了。

    要分配内存,就引出来今天的new和make。

    new

    对于上面的问题我们如何解决呢?既然我们知道了没有为其分配内存,那么我们使用new分配一个吧。

    func main() {
     var i *int
     i=new(int)
     *i=10
     fmt.Println(*i)
    }

    现在再运行程序,完美PASS,打印10。现在让我们看下new这个内置的函数。

    // The new built-in function allocates 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.
    func new(Type) *Type

    它只接受一个参数,这个参数是一个类型,分配好内存后,返回一个指向该类型内存地址的指针。同时请注意它同时把分配的内存置为零,也就是类型的零值。

    我们的例子中,如果没有*i=10,那么打印的就是0。这里体现不出来new函数这种内存置为零的好处,我们再看一个例子。

    func main() {
     u:=new(user)
     u.lock.Lock()
     u.name = "张三"
     u.lock.Unlock()
     fmt.Println(u)
    }
    type user struct {
     lock sync.Mutex
     name string
     age int
    }

    示例中的user类型中的lock字段我不用初始化,直接可以拿来用,不会有无效内存引用异常,因为它已经被零值了。

    这就是new,它返回的永远是类型的指针,指向分配类型的内存地址。

    make

    make也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。

    注意,因为这三种类型是引用类型,所以必须得初始化,但是不是置为零值,这个和new是不一样的。

    func make(t Type, size ...IntegerType) Type

    从函数声明中可以看到,返回的还是该类型。

    二者异同

    所以从这里可以看的很明白了,二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。所以在我们编写程序的时候,就可以根据自己的需要很好的选择了。

    make返回的还是这三个引用类型本身;而new返回的是指向类型的指针。

    其实new不常用

    所以有new这个内置函数,可以给我们分配一块内存让我们使用,但是现实的编码中,它是不常用的。我们通常都是采用短语句声明以及结构体的字面量达到我们的目的,比如:

    i:=0
    u:=user{}

    这样更简洁方便,而且不会涉及到指针这种比麻烦的操作。

    make函数是无可替代的,我们在使用slice、map以及channel的时候,还是要使用make进行初始化,然后才可以对他们进行操作。

  • 相关阅读:
    Android Studio 开发
    Jsp编写的页面如何适应手机浏览器页面
    电影
    Oracle 拆分列为多行 Splitting string into multiple rows in Oracle
    sql server 2008 自动备份
    WINGIDE 激活失败
    python安装 错误 “User installations are disabled via policy on the machine”
    ble编程-外设发送数据到中心
    iOS开发-NSString去掉所有换行及空格
    ios9 字符串与UTF-8 互相转换
  • 原文地址:https://www.cnblogs.com/xhhgo/p/10916254.html
Copyright © 2011-2022 走看看