新函数与未初始化变量的区别

时间:2016-07-23 04:57:56

标签: go

新功能和未初始化变量的区别是什么?两者的优点是什么?

s := new(string) // *string
var s *string    // *string
var s string     // string

这只是为了简化代码吗?因为我认为它是相同的

s := new(string) /* same as */ var s *string = &emptyString

2 个答案:

答案 0 :(得分:4)

此代码:

var s *string

只需将“s”声明为指向字符串的指针即可。在这种情况下,“s”是一个nil指针,这是指针golang中的默认值。

此代码:

s := new(string)

还将“s”声明为指向字符串的指针,但这次是初始化字符串。这意味着“s”是一个非零指针,并指向golang中一个空字符串的字符串的默认值。

See this playground

答案 1 :(得分:2)

第一个区别:

  

内置函数new采用类型T,为a分配存储空间   该类型的变量在运行时

第二个差异: new将已分配的字符串初始化为空字符串(“”)并初始化指向此字符串地址的指针,但var ptr2 *string 只需将ptr2初始化为nil,并且不分配任何字符串:

示例代码A(带注释输出):

ptr := new(string)               // *ptr has value "", ptr: static type *string
fmt.Println(len(*ptr))           // 0
fmt.Println(cap([]byte(*ptr)))   // 32
fmt.Printf("%T %q\n", ptr, *ptr) // *string ""

示例代码B(带注释输出):

var ptr2 *string                // ptr2 has value nil, static type *string
fmt.Printf("%T %#[1]v\n", ptr2) // *string (*string)(nil)
//fmt.Println(len(*ptr2)) // panic: runtime error: invalid memory address or nil pointer dereference
//fmt.Println(cap([]byte(*ptr2)))

示例代码C(带注释输出):

var str string                // str has value "", static type string
fmt.Println(len(str))         // 0
fmt.Println(cap([]byte(str))) // 32
fmt.Printf("%T %[1]q\n", str) // string ""

分配:

  

内置函数new采用类型T,为a分配存储空间   运行时该类型的变量,并返回类型* T的值   指着它。该变量按照中所述进行初始化   关于initial values的部分。

new(T)
     

例如

type S struct { a int; b float64 }
new(S)
     

为S类变量分配存储空间,对其进行初始化(a = 0,   b = 0.0),并返回包含地址的类型* S的值   位置。

参考:https://golang.org/ref/spec

使用新分配:

  

Go有两个分配原语,内置   新功能和制作。他们做不同的事情并适用于   不同的类型,可能会令人困惑,但规则很简单。   我们来谈谈新的第一个。 这是一个分配的内置函数   记忆,但与其他语言中的同名不同   初始化内存,它只将它归零。也就是说,new(T)分配   为类型为T的新项目归零存储并返回其地址,a   类型* T的值。在Go术语中,它返回一个指向新术语的指针   分配了类型为T的零值。

     

由于new返回的内存为零,因此安排很有帮助   在设计数据结构时,每种类型的零值   无需进一步初始化即可使用。这意味着用户   数据结构可以创建一个新的和正确的工作。对于   例如,bytes.Buffer的文档声明“零   Buffer的值是一个可以使用的空缓冲区。“同样,   sync.Mutex没有显式构造函数或Init方法。   相反,sync.Mutex的零值被定义为未锁定   互斥。

     

零价值有用的属性可以传递。考虑一下   类型声明。

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
     

无需进一步安排即可正常使用:

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

使用make进行分配:返回分配。内置功能   make(T,args)的用途与new(T)不同。它创建   切片,地图和通道,它返回一个初始化(不是   归零)T类型的值(不是* T)。区别的原因是   这三种类型代表了数据的引用   必须在使用前初始化的结构。一片,例如,   是一个三项描述符,包含指向数据的指针(在   数组),长度和容量,直到那些项目   初始化后,切片为零。对于切片,地图和通道,make   初始化内部数据结构并为其准备值   使用。例如,

make([]int, 10, 100) 
     

分配一个100个整数的数组,然后创建一个切片结构   长度10,容量100   指向数组的前10个元素。 (制作切片时,   容量可以省略;请参阅切片部分了解更多信息   信息。)相反,new([] int)返回一个新的指针   分配的归零片结构,即指向nil片的指针   值。这些示例说明了new和make之间的区别:

var p *[]int = new([]int)       // allocates slice structure; *p == nil; rarely useful
var v  []int = make([]int, 100) // the slice v now refers to a new array of 100 ints

// Unnecessarily complex:
var p *[]int = new([]int)
*p = make([]int, 100, 100)

// Idiomatic:
v := make([]int, 100)
     

请记住,make仅适用于地图,切片和通道   不返回指针。获取使用new分配的显式指针   或明确地获取变量的地址。

参考:https://golang.org/doc/effective_go.html