We have written one program by which we try to find an address of a constant. Is it possible to do it like that?
package main func main() { const k = 5 address := &k }
It gives an error, can anyone tell how can we find the address of a constant?
In Go, const is a keyword introducing a name for a scalar value such as 2 or 3.14159 or "scrumptious" . Such values, named or otherwise, are called constants in Go. Constants can also be created by expressions built from constants, such as 2+3 or 2+3i or math. Pi/2 or ("go"+"pher") .
Typed constants work like immutable variables can inter-operate only with the same type and untyped constants work like literals can inter-operate with similar types. Constants can be declared with or without a type in Go.
To declare a constant and give it a name, the const keyword is used. Constants cannot be declared using the := syntax.
Naming Conventions for Golang Constants Name of constants must follow the same rules as variable names, which means a valid constant name must starts with a letter or underscore, followed by any number of letters, numbers or underscores. By convention, constant names are usually written in uppercase letters.
In short: you can't.
The error message says:
cannot take the address of k
There are limitations on the operand of the address operator &
. Spec: Address operators:
For an operand
x
of typeT
, the address operation&x
generates a pointer of type*T
tox
. 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 (possibly parenthesized) composite literal. If the evaluation ofx
would cause a run-time panic, then the evaluation of&x
does too.
Constants are not listed as addressable, and things that are not listed in the spec as addressable (quoted above) cannot be the operand of the address operator &
(you can't take the address of them).
It is not allowed to take the address of a constant. This is for 2 reasons:
If you need a pointer to a value being equal to that constant, assign it to a variable of which is addressable so you can take its address, e.g.
func main() { const k = 5 v := k address := &v // This is allowed }
But know that in Go numeric constants represent values of arbitrary precision and do not overflow. When you assign the value of a constant to a variable, it may not be possible (e.g. the constant may be greater than the max value of the variable's type you're assigning it to - resulting in compile-time error), or it may not be the same (e.g. in case of floating point constants, it may lose precision).
I often hit this problem when creating large, nested JSON objects during unit tests. I might have a structure where all the fields are pointers to strings/ints:
type Obj struct { Prop1 *string Prop2 *int Status *string }
and want to write something like:
obj := Obj{ Prop1: &"a string property", Prop2: &5, Status: &statuses.Awesome, }
When I initialise it, but the language doesn't allow this directly. A quick way to bypass this is to define a function that takes a constant and returns its address:
s := func(s string) *string { return &s } i := func(i int) *int { return &i } obj := Obj{ Prop1: s("a string property"), Prop2: i(5), Status: s(statuses.Awesome) }
This works due to the fact that when the constant is passed as a parameter to the function, a copy of the constant is made which means the pointer created in the function does not point to the address of the constant, but to the address of its copy, in the same way as when a constant value is assigned to a var
. However, using a function to do this makes it more readable/less cumbersome IMO than having to forward declare large blocks of variables.
The AWS SDK uses this technique. I now find myself regularly adding a package to my projects that looks something like:
package ref import "time" func Bool(i bool) *bool { return &i } func Int(i int) *int { return &i } func Int64(i int64) *int64 { return &i } func String(i string) *string { return &i } func Duration(i time.Duration) *time.Duration { return &i } func Strings(ss []string) []*string { r := make([]*string, len(ss)) for i := range ss { r[i] = &ss[i] } return r }
Which I call in the following way:
func (t: Target) assignString(to string, value string) { if to == tags.AuthorityId { t.authorityId = ref.String(value) } // ... }
You can also add a deref
package, though I have generally found this to be less useful:
package deref func String(s *string, d string) string { if s != nil { return *s } return d } // more derefs here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With