小智 154
Go有多种内存分配和值初始化方式:
&T{...},&someLocalVar,new,make
创建复合文字时也可以进行分配.
new可用于分配整数等值,&int是非法的:
new(Point)
&Point{} // OK
&Point{2, 3} // Combines allocation and initialization
new(int)
&int // Illegal
// Works, but it is less convenient to write than new(int)
var i int
&i
Run Code Online (Sandbox Code Playgroud)
通过查看以下示例可以看出new和之间的区别make:
p := new(chan int) // p has type: *chan int
c := make(chan int) // c has type: chan int
Run Code Online (Sandbox Code Playgroud)
假设Go没有new和make,但它有内置的功能NEW.然后示例代码如下所示:
p := NEW(*chan int) // * is mandatory
c := NEW(chan int)
Run Code Online (Sandbox Code Playgroud)
这* 是强制性的,所以:
new(int) --> NEW(*int)
new(Point) --> NEW(*Point)
new(chan int) --> NEW(*chan int)
make([]int, 10) --> NEW([]int, 10)
new(Point) // Illegal
new(int) // Illegal
Run Code Online (Sandbox Code Playgroud)
是的,合并new和make成一个单一的内置功能是可能的.但是,单个内置函数很可能会导致新Go程序员比使用两个内置函数更加混乱.
考虑到以上所有要点,它似乎更适合new并make保持独立.
Eva*_*haw 153
你可以做的事情make,你不能做任何其他方式:
这有点难以证明new.它更容易的主要是创建指向非复合类型的指针.以下两个功能是等效的.一个更简洁:
func newInt1() *int { return new(int) }
func newInt2() *int {
var i int
return &i
}
Run Code Online (Sandbox Code Playgroud)
cod*_*boy 24
已经有很多好的答案,但让我解释一下 new() 和 make() 作为单独的分配器的必要性。
当 new() 需要处理其他三种复合类型 - chan、slice 和 map 时,就会出现问题。这三种类型本质上是特殊的,它们的底层类型不仅仅是另一种类型,而是需要初始化的状态。例如,切片的底层状态由指向内部数组存储的第一个元素的指针、确定可以访问的元素数量的长度以及随着元素数量增长而增加的容量组成。new() 当然无法处理此类类型的分配,因为它们需要额外的初始化步骤,这就是 make() 发挥作用的地方。
Sin*_*tra 22
make function仅分配和初始化slice,map或chan类型的对象.像new一样,第一个参数是一个类型.但是,它也可以采取第二个论点,即大小.与new不同,make的返回类型与其参数的类型相同,而不是指向它的指针.并且初始化分配的值(不像新的那样设置为零值).原因是slice,map和chan是数据结构.它们需要初始化,否则它们将无法使用.这就是new()和make()需要不同的原因.
Effective Go的以下示例非常清楚:
p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable
Run Code Online (Sandbox Code Playgroud)
Bho*_*yar 21
换句话说,新分配;进行初始化;
var p *[]int = new([]int)
or
// *p == nil; with len and cap 0
p := new([]int)
Run Code Online (Sandbox Code Playgroud)
这很少有用。
p := make([]int, 0)
Run Code Online (Sandbox Code Playgroud)
我们的切片已初始化,但此处指向一个空数组。
这两个语句都不是很有用,以下是:
var v []int = make([]int, 10, 50)
// Or
v := make([]int, 10, 50)
Run Code Online (Sandbox Code Playgroud)
这会分配一个包含 50 个整数的数组,然后创建一个长度为 10、容量为 50 的切片 v,指向该数组的前 10 个元素。
package main
type Foo map[string]string
type Bar struct {
s string
i int
}
func main() {
// OK:
y := new(Bar)
(*y).s = "hello"
(*y).i = 1
// NOT OK:
z := make(Bar) // compile error: cannot make type Bar
z.s = "hello"
z.i = 1
// OK:
x := make(Foo)
x["x"] = "goodbye"
x["y"] = "world"
// NOT OK:
u := new(Foo)
(*u)["x"] = "goodbye" // !!panic!!: runtime error:
// assignment to entry in nil map
(*u)["y"] = "world"
}
Run Code Online (Sandbox Code Playgroud)
渠道:
func main() {
// OK:
ch := make(chan string)
go sendData(ch)
go getData(ch)
time.Sleep(1e9)
// NOT OK:
ch := new(chan string)
go sendData(ch) // cannot use ch (variable of type *chan string)
// as chan string value in argument to sendData
go getData(ch)
time.Sleep(1e9)
}
func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
}
func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Printf("%s ", input)
}
}
Run Code Online (Sandbox Code Playgroud)
Lor*_*ris 17
new(T)-分配内存,并将其设置为在零值类型Ť ..
..that是0为INT,""对字符串和nil用于被引用类型(切片,地图,CHAN)
需要注意的是被引用类型只是指针一些底层数据结构,这将不会创建由new(T)
实施例:在以下情况下切片,底层阵列将不会被创建,从而new([]int)
将指针返回到什么
make(T)- 为引用的数据类型(slice、map、chan)分配内存,并初始化它们的底层数据结构
示例:在slice 的情况下,将创建具有指定长度和容量的底层数组
请记住,与 C 不同,数组是 Go 中的原始类型!
话虽如此:
make(T) 表现得像复合文字语法
new(T)表现得像var(当变量未初始化时)
func main() {
fmt.Println("-- MAKE --")
a := make([]int, 0)
aPtr := &a
fmt.Println("pointer == nil :", *aPtr == nil)
fmt.Printf("pointer value: %p\n\n", *aPtr)
fmt.Println("-- COMPOSITE LITERAL --")
b := []int{}
bPtr := &b
fmt.Println("pointer == nil :", *bPtr == nil)
fmt.Printf("pointer value: %p\n\n", *bPtr)
fmt.Println("-- NEW --")
cPtr := new([]int)
fmt.Println("pointer == nil :", *cPtr == nil)
fmt.Printf("pointer value: %p\n\n", *cPtr)
fmt.Println("-- VAR (not initialized) --")
var d []int
dPtr := &d
fmt.Println("pointer == nil :", *dPtr == nil)
fmt.Printf("pointer value: %p\n", *dPtr)
}
Run Code Online (Sandbox Code Playgroud)
运行程序
-- MAKE --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- COMPOSITE LITERAL --
pointer == nil : false
pointer value: 0x118eff0 # address to underlying array
-- NEW --
pointer == nil : true
pointer value: 0x0
-- VAR (not initialized) --
pointer == nil : true
pointer value: 0x0
Run Code Online (Sandbox Code Playgroud)
进一步阅读:
https
: //golang.org/doc/effective_go.html#allocation_new https://golang.org/doc/effective_go.html#allocation_make
JRo*_*erC 10
其他答案中详细介绍了“make”的好处,但“New”比上面未提及的 make 有一个额外的好处:泛型(自 1.18 起)。
假设您有一组平面(所有字段都是基元)结构,如下所示:
type SomeStruct struct {
V1 string `json:"v1"`
V2 string `json:"v2"`
}
Run Code Online (Sandbox Code Playgroud)
并且您想要创建一个映射函数,将 map[string]string 转换为任何结构。然后你可以写:
func GetStructFromMap[T any](values map[string]string) (T, error) {
myStr := T{}
bytes, err := json.Marshal(values)
if err != nil {
return *myStr, err
}
if err := json.Unmarshal(bytes, str); err != nil {
return *myStr, err
}
return *myStr, nil
}
Run Code Online (Sandbox Code Playgroud)
但是,对于该行myStr := T{},此代码将引发有关无效复合值的错误。myStr := make(T)通过另一个关于没有基础类型的错误将其替换为will。因此,您将替换将myStr := new(T)创建对结构的归零值实例的引用的行。
可以看出,在处理泛型时,new可以用来实例化编译时未知的类型。
另一方面,您也可以在此特定示例中使用命名返回类型,但更一般的用法仍然有效。
new(T):它返回一个指向 type 类型T值的指针*T,它分配内存并将其归零。new(T)相当于&T{}。
make(T):它返回一个类型T的初始化值,它分配和初始化内存。它用于切片、贴图和通道。
您需要make()创建通道和贴图(和切片,但也可以从阵列创建).没有替代方法来制作这些,所以你无法make()从你的词典中删除.
至于new(),当你可以使用struct语法时,我不知道为什么你需要它.它确实具有独特的语义含义,即"创建并返回一个结构,所有字段都初始化为零值",这可能很有用.
除了Effective Go中解释的所有内容之外,new(T)和之间的主要区别在于&T{}后者显式执行堆分配.但是应该注意,这是依赖于实现的,因此可能会有所变化.
相比make于new没有什么意义,因为这两个执行完全不同的功能.但这在链接文章中有详细解释.
| 归档时间: |
|
| 查看次数: |
64929 次 |
| 最近记录: |