查找go中常数的地址

a14dhokn  于 2024-01-04  发布在  Go
关注(0)|答案(6)|浏览(151)

我们已经写了一个程序,通过它我们试图找到一个常数的地址。有可能这样做吗?

  1. package main
  2. func main() {
  3. const k = 5
  4. address := &k
  5. }

字符串
它给出了一个错误,有人能告诉我们如何找到一个常数的地址吗?

w6mmgewl

w6mmgewl1#

简而言之:你不能。
错误消息显示:
不能取k的地址
地址运算符&的操作数有限制。规格:地址运算符:
对于类型为T的操作数x,地址操作&x生成指向x的类型为*T的指针。操作数必须是 addressable 的,即,要么是变量、指针间接或切片索引操作;要么是可寻址结构操作数的字段选择器;作为可寻址性要求的例外,x也可以是可寻址数组的数组索引操作。如果x的求值会导致运行时出错,那么&x的求值也会导致运行时出错。
常量列为 addressable,并且在规范中没有列为 addressable 的东西(上面引用的)不能成为地址操作符&的操作数(你不能获取它们的地址)。
不允许使用常量的地址。这有两个原因:
1.常量可能根本没有地址。
1.即使一个常量值在运行时存储在内存中,这也是为了帮助运行时保持以下常量:constant。如果你可以接受一个常量的地址,你可以把这个地址(指针)赋给一个变量,你可以改变它。(点的值,常数的值).罗伯特Griesemer(Go语言的作者之一)写了为什么不允许使用字符串字面量的地址:* “如果你能得到一个字符串常量的地址,你可以调用一个函数[赋值给指向的值,导致]可能奇怪的效果-你肯定不希望文字字符串常量改变。
如果你需要一个指针指向一个等于该常数的值,把它赋给一个变量,这个变量是可寻址的,这样你就可以得到它的地址,例如。

  1. func main() {
  2. const k = 5
  3. v := k
  4. address := &v // This is allowed
  5. }

字符串
但是要知道在Go语言中,数字常量代表任意精度的值,并且不会溢出。(例如,常量可能大于您分配给它的变量类型的最大值-导致编译时错误),或者它可能不相同(例如,在浮点常量的情况下,它可能会失去精度)。

展开查看全部
q3aa0525

q3aa05252#

在单元测试中创建大型嵌套JSON对象时,我经常遇到这个问题。我可能有一个结构,其中所有字段都指向字符串/整数:

  1. type Obj struct {
  2. Prop1 *string
  3. Prop2 *int
  4. Status *string
  5. }

字符串
我想写这样的东西:

  1. obj := Obj{
  2. Prop1: &"a string property",
  3. Prop2: &5,
  4. Status: &statuses.Awesome,
  5. }


当我初始化它时,但语言不允许直接这样做。绕过这个问题的一个快速方法是定义一个函数,它接受一个常量并返回其地址:

  1. s := func(s string) *string { return &s }
  2. i := func(i int) *int { return &i }
  3. obj := Obj{
  4. Prop1: s("a string property"),
  5. Prop2: i(5),
  6. Status: s(statuses.Awesome)
  7. }


这是因为当常量作为参数传递给函数时,会生成常量的副本,这意味着在函数中创建的指针并不指向常量的地址,而是指向其副本的地址,与将常量值分配给var时的方式相同。使用函数来做到这一点,使其更具可读性/不那么麻烦IMO比必须向前声明大块的变量。
AWS SDK使用这种技术。我现在发现自己经常向我的项目添加一个包,看起来像这样:

  1. package ref
  2. import "time"
  3. func Bool(i bool) *bool {
  4. return &i
  5. }
  6. func Int(i int) *int {
  7. return &i
  8. }
  9. func Int64(i int64) *int64 {
  10. return &i
  11. }
  12. func String(i string) *string {
  13. return &i
  14. }
  15. func Duration(i time.Duration) *time.Duration {
  16. return &i
  17. }
  18. func Strings(ss []string) []*string {
  19. r := make([]*string, len(ss))
  20. for i := range ss {
  21. r[i] = &ss[i]
  22. }
  23. return r
  24. }


我称之为:

  1. func (t: Target) assignString(to string, value string) {
  2. if to == tags.AuthorityId {
  3. t.authorityId = ref.String(value)
  4. }
  5. // ...
  6. }


你也可以添加一个deref包,尽管我通常发现这不太有用:

  1. package deref
  2. func String(s *string, d string) string {
  3. if s != nil { return *s }
  4. return d
  5. }
  6. // more derefs here.


编辑2022年4月:
随着go 1.18的发布,现在可以定义一个方法来处理所有从常量到指针的转换:

  1. package ref
  2. func Of[E any](e E) *E {
  3. return &e
  4. }

展开查看全部
esyap4oy

esyap4oy3#

这三个选项可能会有所帮助:
1.对泛型使用辅助函数。(适用于原始类型和自定义类型)

  1. package main
  2. import "fmt"
  3. type Role string
  4. const (
  5. Engineer Role = "ENGINEER"
  6. Architect Role = "ARCHITECT"
  7. )
  8. const (
  9. EngineerStr string = "ENGINEER"
  10. ArchitectStr string = "ARCHITECT"
  11. )
  12. func main() {
  13. fmt.Println(PointerTo(Engineer)) // works for custom types
  14. fmt.Println(PointerTo(EngineerStr)) // works for primitive types
  15. }
  16. func PointerTo[T any](v T) *T {
  17. return &v
  18. }

字符串
Try it on playground
1.使用pointy。(仅适用于基元类型)
1.使用ToPointer()方法。(仅适用于自定义类型)

  1. package main
  2. import "fmt"
  3. type Role string
  4. const (
  5. Engineer Role = "ENGINEER"
  6. Architect Role = "ARCHITECT"
  7. )
  8. func (r Role) ToPointer() *Role {
  9. return &r
  10. }
  11. func main() {
  12. fmt.Println(Engineer.ToPointer())
  13. }


Try it on playground

展开查看全部
xkftehaa

xkftehaa4#

我发现了另一种处理此问题的方法,即使用AWS API:

  1. import "github.com/aws/aws-sdk-go/aws"
  2. type Obj struct {
  3. *int
  4. }
  5. x := aws.Int(16) // return address
  6. obj := Obj{x} // work fine

字符串
这个方法和上面的答案是一样的,但是你不需要自己写整个函数。
参见:https://docs.aws.amazon.com/sdk-for-go/api/aws/

tjrkku2a

tjrkku2a5#

你不能,但你可以使用以下命令将const转换为指针:

  1. func ptr[T any](value T) *T {
  2. return &value
  3. }

字符串

zhte4eai

zhte4eai6#

常量部分没有说得很清楚:常量不像变量,不存在于编译的代码或运行的程序中。它们是无类型的,只有当它们被赋值给变量时才会在内存中。
因此,它们的精度是无限的,如果你看this example,你可以看到我可以把常量赋给一个变量,而不需要强制转换,变量将尽可能多地保持常量的精度。
1正如规范还指出的那样,整数至少有256位,浮点数至少有256位尾数和32位指数,如果编译器的内部结构不能准确存储常量,编译器将抛出错误。

相关问题