在Go语言中如何直接在堆上构造一个原始类型?

huangapple go评论91阅读模式
英文:

Construct a primitive type directly on the heap in Go?

问题

如何在Go中直接在堆上构造原始整数类型?

对于复合字面量,支持以下语法:

return &File{fd, name, nil, 0}

但是对于int和其他类型似乎没有类似的等价物:

Size: &uint64(entry.FileInfo.Size()),

>d:\gopath\src\bitbucket.org\anacrolix\dms\dlna\dms\dms.go:271: 无法获取uint64(entry.FileInfo.Size())的地址

英文:

How do I construct a primitive integer type directly on the heap in Go?

For composite literals, the following syntax is supported:

return &File{fd, name, nil, 0}

But no such equivalent seems to exist for int and friends:

Size: &uint64(entry.FileInfo.Size()),

>d:\gopath\src\bitbucket.org\anacrolix\dms\dlna\dms\dms.go:271: cannot take the address of uint64(entry.FileInfo.Size())

答案1

得分: 2

> 地址运算符
>
> 对于类型为 T 的操作数 x,地址操作 &x 会生成一个类型为 *T 的指针指向 x。操作数必须是可寻址的,也就是说,要么是一个变量、指针间接引用或切片索引操作;要么是可寻址结构操作数的字段选择器;要么是可寻址数组的数组索引操作。作为对可寻址要求的例外,x 也可以是一个复合字面量。

原始整数类型是不可寻址的。如果整数是一个寄存器变量,那么它没有内存地址。如果整数是一个常量,提供它的内存地址将允许它被修改。

因此,创建一个整数类型的变量并取其地址,或者使用整数指针类型。例如,

package main

import "fmt"

func main() {
	var i int = 42
	var pi = &i
	j := int(7)
	pj := &j
	var pk = new(int)
	k := *pk
	fmt.Println(i, pi)
	fmt.Println(j, pj)
	fmt.Println(k, pk)
}

输出:

42 0xf840043100
7 0xf840043108
0 0xf840043110
英文:

> Address operators
>
> For an operand x of type T, the address operation &x generates a
> pointer of type *T to x. The operand must be addressable, that is,
> either a variable, pointer indirection, or slice indexing operation;
> or a field selector of an addressable struct operand; or an array
> indexing operation of an addressable array. As an exception to the
> addressability requirement, x may also be a composite literal.

Primitive integer types are not addressable. If the integer is a register variable, there is no memory address. If the integer is a constant, providing its memory address would allow it to be modified.

Therefore, create an integer type variable and take its address or use an integer pointer type. For example,

package main

import "fmt"

func main() {
	var i int = 42
	var pi = &i
	j := int(7)
	pj := &j
	var pk = new(int)
	k := *pk
	fmt.Println(i, pi)
	fmt.Println(j, pj)
	fmt.Println(k, pk)
}

Output:

42 0xf840043100
7 0xf840043108
0 0xf840043110

答案2

得分: 1

使用new关键字初始化一个指向类型的指针,总是在堆上分配内存。

n := new(int64)
*n = entry.FileInfo.Size()
return n

你也可以直接取一个在栈上分配的整数的地址。
当返回一个指向在栈上分配的对象的指针时,Go的逃逸分析会确保该对象被提升到堆上。虽然这不会立即在堆上分配内存,但最终会在堆上分配。

n := entry.FileInfo.Size()
return &n

至于你关于为什么对于基本类型不能使用&T{}的方法的问题,我似乎忘记了。我确实知道有一个很好的理由,但也许有更有知识的人可以给我们解释这个问题。

英文:

Initializing a pointer to a type using new, always allocates it on the heap.

n := new(int64)
*n = entry.FileInfo.Size()
return &n

You can also just take the address of a stack allocated integer.
When returning a pointer to a stack allocated object, Go's escape analysis will ensure this object is promoted to the heap. While this does not immediately allocate it on the heap, it will end up there.

n := entry.FileInfo.Size()
return &n

As to your question on why the &T{} approach does not work for primitives, I seem to have forgot. I do know there was a good reason for it, but perhaps someone more knowledgeable can enlighten us on this matter.

huangapple
  • 本文由 发表于 2012年10月14日 18:03:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/12881175.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定