zoukankan      html  css  js  c++  java
  • new() 和 make() 的区别 var arr1 = new([5]int) var arr2 [5]int

    实践:

    1)

    m := make(map[string]string)
    n := new(map[string]string)
    fmt.Println(m)
    fmt.Println(n)

    fmt.Println("&m", &m)
    fmt.Println("&n", &n)

    m["k"] = "v"
    fmt.Println(m)

    (*n)["k"] = "v"
    fmt.Println(n)

    map[]
    &map[]
    &m &map[]
    &n 0xc000092168
    map[k:v]
    panic: assignment to entry in nil map




    Effective Go - The Go Programming Language https://golang.org/doc/effective_go.html#allocation_new

    Allocation with new

    Go has two allocation primitives, the built-in functions new and make. They do different things and apply to different types, which can be confusing, but the rules are simple. Let's talk about new first. It's a built-in function that allocates memory, but unlike its namesakes in some other languages it does not initialize the memory, it only zeros it. That is, new(T) allocates zeroed storage for a new item of type T and returns its address, a value of type *T. In Go terminology, it returns a pointer to a newly allocated zero value of type T.

    Since the memory returned by new is zeroed, it's helpful to arrange when designing your data structures that the zero value of each type can be used without further initialization. This means a user of the data structure can create one with new and get right to work. For example, the documentation for bytes.Buffer states that "the zero value for Buffer is an empty buffer ready to use." Similarly, sync.Mutex does not have an explicit constructor or Init method. Instead, the zero value for a sync.Mutex is defined to be an unlocked mutex.

    The zero-value-is-useful property works transitively. Consider this type declaration.

    type SyncedBuffer struct {
        lock    sync.Mutex
        buffer  bytes.Buffer
    }
    

    Values of type SyncedBuffer are also ready to use immediately upon allocation or just declaration. In the next snippet, both p and v will work correctly without further arrangement.

    p := new(SyncedBuffer)  // type *SyncedBuffer
    var v SyncedBuffer      // type  SyncedBuffer
    

     

     

    the-way-to-go_ZH_CN/06.5.md at master · Unknwon/the-way-to-go_ZH_CN https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.5.md

    new、make new 和 make 均是用于分配内存:new 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。它们的用法就像是函数,但是将类型作为参数:new(type)、make(type)。new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针(详见第 10.1 节)。它也可以被用于基本类型:v := new(int)。make(T) 返回类型 T 的初始化之后的值,因此它比 new 进行更多的工作(详见第 7.2.3/4 节、第 8.1.1 节和第 14.2.1 节)new() 是一个函数,不要忘记它的括号

    src/builtin/builtin.go:189

    // The make built-in function allocates and initializes an object of type
    // slice, map, or chan (only). Like new, the first argument 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:
    // Slice: The size specifies the length. The capacity of the slice is
    // equal to its length. A second integer argument may be provided to
    // specify a different capacity; it must be no smaller than the
    // length. For example, make([]int, 0, 10) allocates an underlying array
    // of size 10 and returns a slice of length 0 and capacity 10 that is
    // backed by this underlying array.
    // Map: An empty map is allocated with enough space to hold the
    // specified number of elements. The size may be omitted, in which case
    // a small starting size is allocated.
    // Channel: The channel's buffer is initialized with the specified
    // buffer capacity. If zero, or the size is omitted, the channel is
    // unbuffered.
    func make(t Type, size ...IntegerType) Type

    // 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

    7.2.4 new() 和 make() 的区别

    看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

    • new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为*T的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体(参见第 10 章);它相当于 &T{}
    • make(T) 返回一个类型为 T 的初始值,它只适用于3种内建的引用类型:切片、map 和 channel(参见第 8 章,第 13 章)。

    换言之,new 函数分配内存,make 函数初始化;

    https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md

     

    the-way-to-go_ZH_CN/10.2.md at master · Unknwon/the-way-to-go_ZH_CN https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/10.2.md

    10.2 使用工厂方法创建结构体实例

    10.2.1 结构体工厂

    Go 语言不支持面向对象编程语言中那样的构造子方法,但是可以很容易的在 Go 中实现 “构造子工厂”方法。为了方便通常会为类型定义一个工厂,按惯例,工厂的名字以 new 或 New 开头。假设定义了如下的 File 结构体类型:

    type File struct {
        fd      int     // 文件描述符
        name    string  // 文件名
    }

    下面是这个结构体类型对应的工厂方法,它返回一个指向结构体实例的指针:

    func NewFile(fd int, name string) *File {
        if fd < 0 {
            return nil
        }
    
        return &File{fd, name}
    }

    然后这样调用它:

    f := NewFile(10, "./test.txt")

    在 Go 语言中常常像上面这样在工厂方法里使用初始化来简便的实现构造函数。

    如果 File 是一个结构体类型,那么表达式 new(File) 和 &File{} 是等价的。

    这可以和大多数面向对象编程语言中笨拙的初始化方式做个比较:File f = new File(...)

    我们可以说是工厂实例化了类型的一个对象,就像在基于类的OO语言中那样。

    如果想知道结构体类型T的一个实例占用了多少内存,可以使用:size := unsafe.Sizeof(T{})

    如何强制使用工厂方法

    通过应用可见性规则参考4.2.1节9.5 节就可以禁止使用 new 函数,强制用户使用工厂方法,从而使类型变成私有的,就像在面向对象语言中那样。

    type matrix struct {
        ...
    }
    
    func NewMatrix(params) *matrix {
        m := new(matrix) // 初始化 m
        return m
    }

    在其他包里使用工厂方法:

    package main
    import "matrix"
    ...
    wrong := new(matrix.matrix)     // 编译失败(matrix 是私有的)
    right := matrix.NewMatrix(...)  // 实例化 matrix 的唯一方式

    10.2.2 map 和 struct vs new() 和 make()

    new 和 make 这两个内置函数已经在第 7.2.4 节通过切片的例子说明过一次。

    现在为止我们已经见到了可以使用 make() 的三种类型中的其中两个:

    slices  /  maps / channels(见第 14 章)

    下面的例子说明了在映射上使用 new 和 make 的区别以及可能发生的错误:

    示例 10.4 new_make.go(不能编译)

    package main
    
    type Foo map[string]string
    type Bar struct {
        thingOne string
        thingTwo int
    }
    
    func main() {
        // OK
        y := new(Bar)
        (*y).thingOne = "hello"
        (*y).thingTwo = 1
    
        // NOT OK
        z := make(Bar) // 编译错误:cannot make type Bar
        (*z).thingOne = "hello"
        (*z).thingTwo = 1
    
        // OK
        x := make(Foo)
        x["x"] = "goodbye"
        x["y"] = "world"
    
        // NOT OK
        u := new(Foo)
        (*u)["x"] = "goodbye" // 运行时错误!! panic: assignment to entry in nil map
        (*u)["y"] = "world"
    }

    试图 make() 一个结构体变量,会引发一个编译错误,这还不是太糟糕,但是 new() 一个映射并试图使用数据填充它,将会引发运行时错误! 因为 new(Foo) 返回的是一个指向 nil 的指针,它尚未被分配内存。所以在使用 map 时要特别谨慎。

    链接

    the-way-to-go_ZH_CN/04.2.md at master · Unknwon/the-way-to-go_ZH_CN https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.2.md

    可见性规则

    当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。

    问题 7.1 下面代码段的输出是什么?

    a := [...]string{"a", "b", "c", "d"}
    for i := range a {
    	fmt.Println("Array item", i, "is", a[i])
    }

    Go 语言中的数组是一种 值类型(不像 C/C++ 中是指向首元素的指针),所以可以通过 new() 来创建: var arr1 = new([5]int)

    那么这种方式和 var arr2 [5]int 的区别是什么呢?arr1 的类型是 *[5]int,而 arr2的类型是 [5]int

    这样的结果就是当把一个数组赋值给另一个时,需要再做一次数组内存的拷贝操作。例如:

    arr2 := *arr1
    arr2[2] = 100

    这样两个数组就有了不同的值,在赋值后修改 arr2 不会对 arr1 生效。

    所以在函数中数组作为参数传入时,如 func1(arr2),会产生一次数组拷贝,func1 方法不会修改原始的数组 arr2。

    如果你想修改原数组,那么 arr2 必须通过&操作符以引用方式传过来,例如 func1(&arr2),下面是一个例子

    示例 7.2 pointer_array.go:

    package main
    import "fmt"
    func f(a [3]int) { fmt.Println(a) }
    func fp(a *[3]int) { fmt.Println(a) }
    
    func main() {
    	var ar [3]int
    	f(ar) 	// passes a copy of ar
    	fp(&ar) // passes a pointer to ar
    }

    输出结果:

    [0 0 0]
    &[0 0 0]

    另一种方法就是生成数组切片并将其传递给函数(详见第 7.1.4 节)。

  • 相关阅读:
    ubuntu 下安装Angular2-cli脚手架
    git的使用及常用命令(二)
    framework7+node+mongo项目
    LINUX下安装搭建nodejs及创建nodejs-express-mongoose项目
    初学strurs基础
    JAVA Struts2 搭建
    mongodb的基本操作
    LightOj_1342 Aladdin and the Magical Sticks
    Codeforces Round #Pi (Div. 2)
    Codeforces Round #315 (Div. 2)
  • 原文地址:https://www.cnblogs.com/rsapaper/p/9620541.html
Copyright © 2011-2022 走看看