|
我有一个带*int结构类型64字段。
% i( L( j0 @2 jtype SomeType struct SomeField *int64}4 N$ s& A" m+ f, P$ V! D
在我的代码中的某个时候,我想声明一个词(例如,当我知道值应该是 0或指向 0时,你知道我的意思)
0 p- W$ c; Q8 ?7 N% s3 z- Uinstance := SomeType{ SomeField: &0,}
( e4 S9 {1 K; x" ~ …除了这不起作用& A0 \ `4 `) y/ r; y, p
./main.go:xx: cannot use &0 (type *int) as type *int64 in field value4 ?' ^" L$ h3 O' H8 m" p' G
所以我试试这个
1 X, ?( [, E4 ]4 ^/ p
! v; }) w- l+ _! n0 u; q- instance := SomeType{ SomeField: &int64(0)code]…但这也不起作用[code]./main.go:xx: cannot take the address of int64(0)
; H. t: G/ A5 t/ \) y" A+ b, }- f 我该怎么办?我能想出的唯一解决办法是使用占位符变量0 O; o) i9 i3 g! U
var placeholder int64placeholder = 0instance := SomeType{ SomeField: &placeholder,}: s! [6 S. d: r+ W/ a( O }1 I- J
编辑:
+ G. {" a6 U% y0 }1 |显然,我的问题很模糊。我正在寻找一种字面说明a 的方法*int64.这可以用于构造函数,或解释文本结构值,甚至作为其他函数的参数。但辅助函数或使用不同类型并不是我正在寻找的解决方案。* q8 X* {# f2 J7 X9 Y, l
/ a* u( K. O5 Z+ R% G3 h/ [/ E 解决方案:
1 n: _: S9 ~' U! `, k& ^ Go 语言规范(地址操作符)不允许获得数字常量地址(不是无类型常量也不是类型常量)。
5 i1 S$ _1 Y2 [* {操作数必须是可寻址的,也就是说,变量、指针间接或切片索引操作;或字段选择器可以找到结构操作的数量;或数组索引操作可以找到数组。作为可搜索要求的例外,x[在&x]复合文字也可以在表达式中使用。
6 S" V3 R, |3 o9 t- N& W你的选择(在Go Playground尝试所有选项:
+ O& f) o: G% C4 b1 i# {1) 与 new()您可以简单地使用内置new()函数分配新的零值int64并获地址:
) y+ g P& ]: W9 ]instance := SomeType{ SomeField: new(int64),}' |4 {! Q' D* w x7 q; p1 c
但请注意,这只能用于指向任何类型的零值指针的分配和获取。0 n2 I! K& f( v: u
2) 带辅助变量对于非零元素,最简单和推荐的是使用可获取地址的辅助变量:* |( |0 v( y1 G% P
helper := int64(2)instance2 := SomeType{ SomeField: &helper,}
, {9 @" }0 l7 d' G* ^3 u, W 3) 具有辅助功能注意:在我的github.com/icza/gox库中,gox该包提供辅助函数,用于获取指向非零值的指针,因此您不必将其添加到您需要的所有项目中。
" } I9 x: V- {% X4 j或者,如果您多次需要此功能,您可以创建一个辅助函数来分配和返回一个函数*int64:
6 O* ^4 w9 m% k O' w7 R X' b+ kfunc create(x int64) *int64 { return &x}+ c) G1 r9 R' p& [
并使用它:! v2 o3 D5 K% e# z- Z g+ z
6 n4 o' W& u, |( d7 m Q; z
- instance3 := SomeType{ SomeField: create(3)code]请注意,我们实际上没有分配任何东西,Go 当我们返回函数参数地址时,编译器就这样做了。Go 编译器进行转义分析,并在堆(而不是堆栈)上分配局部变量(如果可能转义函数)。详细信息,
2 S$ D. q& m/ N - 4) 带单行匿名函数[code]instance4 := SomeType{ SomeField: func() *int64 { i := int64(4); return &i}code]或者作为(短)替代方案:
; u% u# u4 U Q+ Y9 o9 u - [code]instance4 := SomeType{ SomeField: func(i int64) *int64 { return &i }code]5) 带切片的字面量、索引和地址如果你想*SomeField要成为别人0,你需要一些可以找到的东西。7 [' n4 |9 E4 M, Y! `
- 你还能做到,但这很丑:[code]instance5 := SomeType{ SomeField: &[]int64{5}[0]fmt.Println(*instance2.SomeField) // Prints 5
5 x, e f4 p$ G4 u 这里发生的是一个[]int64切片是用文字创建的,有一个元素 ( 5)。并且它被索引(第0个元素)并取第0个元素的地址。在后台,一个 的数组[1]int64也将分配并用作切片的后备数组。所以这里有很多样板。
* K. Z c" X$ P, J) d( B6) 使用辅助结构文字让我们检查可寻址性要求的例外情况:
9 p0 Q! Q/ Q8 \作为可寻址要求的例外,x[在&x]复合文字也可以在表达式中使用。: ]3 J/ r* t1 f$ S# p) [3 j! X
这意味着使用复合文本的地址,如结构文本。如果我们这样做,我们将分配结构值并获得指向它的指针。但如果是这样,我们可以使用另一个要求:字段选择器可以找到结构操作数。因此,如果结构体的字面量包含 type 字段int我们还可以获得该字段的地址!
+ A- ~1 F- K1 t. i0 J( e让我们来看看这个选项的实际效果。我们将使用这种包装结构类型:6 |0 j# Z" I" G+ w4 h& `6 k
type intwrapper struct x int64}; n! f/ T+ F4 a5 g' K) b
现在我们可以这样做了:
& n. Z1 R$ y$ _' p! a+ m0 ]instance6 := SomeType{ SomeField: &(&intwrapper{6}).x,}5 g Q4 |7 w) l5 d7 T9 s: E
请注意,这
8 |* v, d0 d8 _) B; ^" u2 o& K&(&intwrapper{6}).x' n7 z# C& G( [" ?4 o
意思如下:
" w3 Q' J/ J1 d9 Z1 f! x1 Q& ( (&intwrapper{6}).x )& Y4 |# o9 a5 ]' Y, i
但由于地址运算符号,我们可以省略外括号&应用于选择器表达式结果。
% T2 x5 G5 z# K8 O: x8 [- K请注意,以下情况会发生在后台(这也是一种有效的语法):" T a# r. V; m- V
&(*(&intwrapper{6})).x
) ], U& ~5 N5 W& B# s6 l/ \( w9 r 7) 使用辅助匿名结构文字原理与案例#6 是一样的,但我们也可以使用匿名结构的字面量,所以我们不需要定义帮助器/包装器的结构类型:& B( A1 ^% f X9 z0 }* f) M
instance7 := SomeType{ SomeField: &(&struct{ x int64 }{7}).x,}" M4 c0 }& l2 \
|
|