zoukankan      html  css  js  c++  java
  • Go语言new和make的区别

    一.简单说明

    方法 作用 作用对象 返回值
    new 分配内存 值类型和用户定义的类型 初始化为零值,返回指针
    make 分配内存 内置引用类型(map,slice,channel) 初始化为零值,返回引用类型本身

    1.1 new的主要特性

    new是内建函数,可以参考如下代码定义:

    func new(Type) *Type 
    

    内建函数new用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值得指针。
    根据上述的描述,可以自己实现一个类型new的功能:

    func newInt() *int {
      var i int
      return &i
    }
    
    someInt := newInt()
    

    这个函数的功能和somInt := new(int)一模一样,所以我们在定义new开头的函数时,出于约定也应该返回类型的指针。

    1.2 make的主要特性

    make也是内建函数,它的定义比new多了一个参数,返回值也不同。可以参考如下的代码定义:

    func make(Type, size IntegerType) Type
    

    make是用来初始化map,slice,channel这几种特定类型的。编译过程中,用make去初始化不同的类型会调用不同的底层函数:

    • 1.初始化map,调用runtime.makemap
    • 2.初始化slice,调用runtime.makeslice
    • 3.初始化channel,调用runtime.makechan

    接下来了解下函数的源码:

    • runtime.makemap
    // path: src/runtime/map.go
    func makemap(t *maptype, hint int, h *hmap) *hmap {
        ...
       // 初始化 Hmap
       if h == nil {
          h = new(hmap)
       }
    
       // 生成 hash 种子
       h.hash0 = fastrand()
    
       // 计算 桶 的数量
       B := uint8(0)
       for overLoadFactor(hint, B) {
          B++
       }
       h.B = B
       if h.B != 0 {
          var nextOverflow *bmap
    
          // 创建 桶
          h.buckets, nextOverflow = makeBucketArray(t, h.B, nil)
          ...
       }
       return h
    }
    
    • runtime.makeslice
    // path: src/runtime/slice.go
    func makeslice(et *_type, len, cap int) unsafe.Pointer {
        // 计算占用空间和是否溢出
        mem, overflow := math.MulUintptr(et.size, uintptr(cap))
    
       // 一些边界条件处理 
        if overflow || mem > maxAlloc || len < 0 || len > cap {
            mem, overflow := math.MulUintptr(et.size, uintptr(len))
            if overflow || mem > maxAlloc || len < 0 {
               // panic: len 超出范围 
                panicmakeslicelen()
            }
            // panic: cap 超出范围 
            panicmakeslicecap()
        }
    
        return mallocgc(mem, et, true)
    }
    
    • runtime.makechan
    // path: src/runtime/chan.go
    func makechan(t *chantype, size int) *hchan {
       ...
       var c *hchan
    
       // 针对不同情况下对 channel 实行不同的内存分配策略
       switch {
       case mem == 0:
          // 无缓冲区,只给 hchan 分配一段内存
          c = (*hchan)(mallocgc(hchanSize, nil, true))
          c.buf = c.raceaddr()
       case elem.ptrdata == 0:
          // channel 不包含指针,给 hchan 和 缓冲区分配一段连续的内存
          c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
          c.buf = add(unsafe.Pointer(c), hchanSize)
       default:
          // 单独给 hchan 和 缓冲区分配内存
          c = new(hchan)
          c.buf = mallocgc(mem, elem, true)
       }
    
       // 初始化 hchan 的内部字段 
       c.elemsize = uint16(elem.size)
       c.elemtype = elem
       c.dataqsiz = uint(size)
       ...
    }
    

    1.3 总结

    make相对于new来说,做的事情更多,new只是开辟了内存空间, make为更加复杂的数据结构开辟内存空间并对一些字段进行初始化

  • 相关阅读:
    塔防游戏 代码project as 分享
    iOS网络监控— BMReachability
    Oracle学习(五):多表查询
    Servlet之生命周期【入门版(刚開始学习的人必看)】
    mysql 流程函数 存储引擎 InnoDB简单特性
    js
    UVa 10245
    Ubuntu14.04怎样使用root登录
    leetCode(29):Happy Number
    WebService:asp.net类库中添加WebService引用出现问题解决方法
  • 原文地址:https://www.cnblogs.com/yuhaohao/p/14622675.html
Copyright © 2011-2022 走看看