Đặc tả Ngôn ngữ Go ( Toán tử địa chỉ ) không cho phép lấy địa chỉ của một hằng số (không phải của một hằng số chưa được định kiểu cũng như không phải của một hằng số được định kiểu ).
Toán hạng phải có thể định địa chỉ được , nghĩa là một biến, hướng con trỏ hoặc thao tác lập chỉ mục lát cắt; hoặc một bộ chọn trường của toán hạng cấu trúc có thể định địa chỉ; hoặc hoạt động lập chỉ mục mảng của một mảng có thể định địa chỉ. Là một ngoại lệ đối với yêu cầu về khả năng giải quyết, x
[trong biểu thức của &x
] cũng có thể là một chữ tổng hợp (có thể được đặt trong ngoặc đơn) .
Để biết lý do tại sao điều này không được phép, hãy xem câu hỏi liên quan: Tìm địa chỉ của hằng số khi di chuyển . Một câu hỏi tương tự (tương tự không được phép lấy địa chỉ của nó): Làm cách nào để lưu trữ tham chiếu đến kết quả của một thao tác trong Go?
Tùy chọn của bạn (thử tất cả trên Go Playground ):
1) Với new()
Bạn chỉ cần sử dụng new()
hàm nội trang để cấp phát một giá trị 0 mới int64
và lấy địa chỉ của nó:
instance := SomeType{
SomeField: new(int64),
}
Nhưng lưu ý rằng điều này chỉ có thể được sử dụng để cấp phát và lấy một con trỏ đến giá trị 0 của bất kỳ kiểu nào.
2) Với biến trợ giúp
Đơn giản nhất và được khuyến nghị cho các phần tử khác 0 là sử dụng biến trợ giúp có địa chỉ có thể được sử dụng:
helper := int64(2)
instance2 := SomeType{
SomeField: &helper,
}
3) Với chức năng trợ giúp
Lưu ý: Các hàm trợ giúp để thu được một con trỏ đến giá trị khác 0 có sẵn trong github.com/icza/gox
thư viện của tôi , trong gox
gói, vì vậy bạn không cần phải thêm chúng vào tất cả các dự án của mình khi bạn cần.
Hoặc nếu bạn cần điều này nhiều lần, bạn có thể tạo một hàm trợ giúp phân bổ và trả về *int64
:
func create(x int64) *int64 {
return &x
}
Và sử dụng nó:
instance3 := SomeType{
SomeField: create(3),
}
Lưu ý rằng chúng tôi thực sự không cấp phát bất cứ thứ gì, trình biên dịch Go đã làm điều đó khi chúng tôi trả về địa chỉ của đối số hàm. Trình biên dịch Go thực hiện phân tích thoát và phân bổ các biến cục bộ trên heap (thay vì ngăn xếp) nếu chúng có thể thoát khỏi hàm. Để biết chi tiết, hãy xem Trả về một phần của mảng cục bộ trong hàm Go có an toàn không?
4) Với chức năng ẩn danh một lớp
instance4 := SomeType{
SomeField: func() *int64 { i := int64(4); return &i }(),
}
Hoặc như một giải pháp thay thế (ngắn hơn):
instance4 := SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}
5) Với phần chữ, lập chỉ mục và lấy địa chỉ
Nếu bạn muốn *SomeField
khác hơn 0
, thì bạn cần một cái gì đó có thể giải quyết.
Bạn vẫn có thể làm điều đó, nhưng điều đó thật tệ:
instance5 := SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5
Điều xảy ra ở đây là một []int64
lát cắt được tạo bằng một chữ, có một phần tử ( 5
). Và nó được lập chỉ mục (phần tử thứ 0) và địa chỉ của phần tử thứ 0 được lấy. Trong nền, một mảng [1]int64
cũng sẽ được cấp phát và sử dụng làm mảng hỗ trợ cho lát cắt. Vì vậy, có rất nhiều bảng điều khiển ở đây.
6) Với một chữ cấu trúc trợ giúp
Hãy xem xét ngoại lệ đối với các yêu cầu về khả năng giải quyết:
Là một ngoại lệ đối với yêu cầu về khả năng giải quyết, x
[trong biểu thức của &x
] cũng có thể là một chữ tổng hợp (có thể được đặt trong ngoặc đơn) .
Điều này có nghĩa là lấy địa chỉ của một ký tự tổng hợp, ví dụ như một ký tự cấu trúc là ok. Nếu chúng ta làm như vậy, chúng ta sẽ có giá trị struct được phân bổ và một con trỏ thu được đến nó. Nhưng nếu vậy, một yêu cầu khác sẽ có sẵn cho chúng tôi: "bộ chọn trường của toán hạng cấu trúc có thể địa chỉ" . Vì vậy, nếu ký tự struct chứa một trường kiểu int64
, chúng ta cũng có thể lấy địa chỉ của trường đó!
Hãy xem tùy chọn này hoạt động. Chúng tôi sẽ sử dụng loại cấu trúc trình bao bọc này:
type intwrapper struct {
x int64
}
Và bây giờ chúng ta có thể làm:
instance6 := SomeType{
SomeField: &(&intwrapper{6}).x,
}
Lưu ý rằng điều này
&(&intwrapper{6}).x
nghĩa là như sau:
& ( (&intwrapper{6}).x )
Nhưng chúng ta có thể bỏ qua dấu ngoặc đơn "bên ngoài" vì toán tử địa chỉ &
được áp dụng cho kết quả của biểu thức bộ chọn .
Cũng lưu ý rằng trong nền, điều sau sẽ xảy ra (đây cũng là một cú pháp hợp lệ):
&(*(&intwrapper{6})).x
7) Với nghĩa đen cấu trúc ẩn danh trợ giúp
Nguyên tắc giống như trường hợp số 6, nhưng chúng ta cũng có thể sử dụng một nghĩa đen struct ẩn danh, vì vậy không cần định nghĩa kiểu cấu trúc helper / wrapper:
instance7 := SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}