How to obtain the address of an object referenced by an interface - go

I have two interface objects which I would like to compare against each other. I don't only want to compare if their values are the same, I also want to know whether these two interfaces are referencing the same object or if they're referencing two different objects with equal values.
Is there some way to extract the address an interface references from an interface object? Then I could just compare the two addresses to know whether the two interfaces reference the same object.

If two interfaces have pointer values, then you can simply compare them:
func cmp(v1, v2 interface{}) bool {
return v1==v2
}
func main() {
a:=1
b:=1
c:=&a
cmp(&a,&b) // false
cmp(a, b) // true, compare values
cmp(c, &a) // true
}

Be careful here.
Two different interface values can never "reference" the "same object" as an interface value always contains a copy of the value you wrap in the interface value. Variable identity (your "same object") would be "equal address" which is undefined for values wrapped in an interface value as these wrapped values are not addressable. So a clear no to your question.
But of course you can store a pointer to your value in the interface value iff the pointer type satisfies the interface.
It is best avoided to talk about "object" and "reference". Go has values of certain types. Some values are addressable. You can store addresses of addressable values in appropriately typed pointer variables.

Related

Operation applied on values of a type

As mentioned in Go specification:
"A type determines a set of values together with operations and methods specific to those values."
To introduce an operation or method to be applied on the values of a type,
Is that operation applied on values (taken from a set) supposed to give the result (or value) from the same set?
For example, in the below code, findName() is not supposed to be a method on type user. Instead findName() should be a helper function.
type user struct {
name string
email string
age int
}
func (u user) findElder(other user) user {
if u.age >= other.age {
return u
}
return other
}
func (u user) findName() string {
return u.name
}
"operations and methods specific to those values" does not mean that they are unique to those values, or that they result in those values.
According to Google, "specific" means "clearly defined or identified." In this quote from the Go spec, the word "specific" is used with regard to the fact that Go is strongly typed, meaning that operations and methods work on the types that they are defined or identified to work on.
For example, the == operator is specified to work on integer types, thus, the == operator is specific to values of int, int32, uint8, etc.
No, I don't think that the operation applied on values (taken from a set) are supposed to give the result (or value), only from the same set. They can be from a different set of values as well. It all depends on the use case, the design of the type and the operation.
So in your case, findName() can very well be a method even though it is returning something not in the set of input values.

Use map[string]SpecificType with method of map[string]SomeInterface into

I get cannot use map[string]MyType literal (type map[string]MyType) as type map[string]IterableWithID in argument to MapToList with the code below, how do I pass in a concrete map type to method that expects a interface type?
https://play.golang.org/p/G7VzMwrRRw
Go's interface convention doesn't quite work the same way as in, say, Java (and the designers apparently didn't like the idea of getters and setters very much :-/ ). So you've got two core problems:
A map[string]Foo is not the same as a map[string]Bar, even if Bar implements Foo, so you have to break it out a bit (use make() beforehand, then assign in a single assignment).
Interface methods are called by value with no pointers, so you really need to do foo = foo.Method(bar) in your callers or get really pointer-happy to implement something like this.
What you can do to more-or-less simulate what you want:
type IterableWithID interface {
SetID(id string) IterableWithID // use as foo = foo.SetID(bar)
}
func (t MyType) SetID(id string) IterableWithID {
t.ID = id
return t
}
...and to deal with the typing problem
t := make(map[string]IterableWithID)
t["foo"] = MyType{}
MapToList(t) // This is a map[string]IterableWithID, so compiler's happy.
...and finally...
value = value.SetID(key) // We set back the copy of the value we mutated
The final value= deals with the fact that the method gets a fresh copy of the value object, so the original would be untouched by your method (the change would simply vanish).
Updated code on the Go Playground
...but it's not particularly idiomatic Go--they really want you to just reference struct members rather than use Java-style mutators in interfaces (though TBH I'm not so keen on that little detail--mutators are supes handy to do validation).
You can't do what you want to do because the two map types are different. It doesn't matter that the element type of one is a type that implements the interface which is the element type of the other. The map type that you pass into the function has to be map[string]IterableWithID. You could create a map of that type, assign values of type MyType to the map, and pass that to the function.
See https://play.golang.org/p/NfsTlunHkW
Also, you probably don't want to be returning a pointer to a slice in MapToList. Just return the slice itself. A slice contains a reference to the underlying array.

Why do I get a "cannot assign" error when setting value to a struct as a value in a map? [duplicate]

This question already has answers here:
Accessing struct fields inside a map value (without copying)
(2 answers)
Closed 7 years ago.
New to Go. Encountered this error and have had no luck finding the cause or the rationale for it:
If I create a struct, I can obviously assign and re-assign the values no problem:
type Person struct {
name string
age int
}
func main() {
x := Person{"Andy Capp", 98}
x.age = 99
fmt.Printf("age: %d\n", x.age)
}
but if the struct is one value in a map:
type Person struct {
name string
age int
}
type People map[string]Person
func main() {
p := make(People)
p["HM"] = Person{"Hank McNamara", 39}
p["HM"].age = p["HM"].age + 1
fmt.Printf("age: %d\n", p["HM"].age)
}
I get cannot assign to p["HM"].age. That's it, no other info. http://play.golang.org/p/VRlSItd4eP
I found a way around this - creating an incrementAge func on Person, which can be called and the result assigned to the map key, eg p["HM"] = p["HM"].incrementAge().
But, my question is, what is the reason for this "cannot assign" error, and why shouldn't I be allowed to assign the struct value directly?
p["HM"] isn't quite a regular addressable value: hashmaps can grow at runtime, and then their values get moved around in memory, and the old locations become outdated. If values in maps were treated as regular addressable values, those internals of the map implementation would get exposed.
So, instead, p["HM"] is a slightly different thing called a "map index expression" in the spec; if you search the spec for the phrase "index expression" you'll see you can do certain things with them, like read them, assign to them, and use them in increment/decrement expressions (for numeric types). But you can't do everything. They could have chosen to implement more special cases than they did, but I'm guessing they didn't just to keep things simple.
Your approach seems good here--you change it to a regular assignment, one of the specifically-allowed operations. Another approach (maybe good for larger structs you want to avoid copying around?) is to make the map value a regular old pointer that you can modify the underlying object through:
package main
import "fmt"
type Person struct {
name string
age int
}
type People map[string]*Person
func main() {
p := make(People)
p["HM"] = &Person{"Hank McNamara", 39}
p["HM"].age += 1
fmt.Printf("age: %d\n", p["HM"].age)
}
The left side of the assignment must b "addressable".
https://golang.org/ref/spec#Assignments
Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier.
and https://golang.org/ref/spec#Address_operators
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 #twotwotwo's comment, p["HM"] is not addressable.
but, there is no such definition show what is "addressable struct operand" in the spec. I think they should add some description for it.

this code uses the address of type?

the code at https://code.google.com/p/goauth2/source/browse/oauth/oauth.go#99 declares this type:
package oauth
...
type Config struct {...}
...
the suggested use of this is following:
var config = &oauth.Config{...}
I do not understand why this code takes the address of this type and why this is even possible in Go. I am a newbie. I thought that types are for the compiler, no? Please help.
The Go Programming Language Specification
Composite literals
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the value followed by a brace-bound list of composite
elements. An element may be a single expression or a key-value pair.
Given the declaration
type Point3D struct { x, y, z float64 }
one may write
origin := Point3D{} // zero value for Point3D
Taking the address of a composite literal generates a pointer to a
unique instance of the literal's value.
var pointer *Point3D = &Point3D{y: 1000}
It's an example of the use of a pointer to a composite literal.
This is taking the address of a new instance of the Config type, not the address of the type itself.

Properly distinguish between not set (nil) and blank/empty value

Whats the correct way in go to distinguish between when a value in a struct was never set, or is just empty, for example, given the following:
type Organisation struct {
Category string
Code string
Name string
}
I need to know (for example) if the category was never set, or was saved as blank by the user, should I be doing this:
type Organisation struct {
Category *string
Code *string
Name *string
}
I also need to ensure I correctly persist either null or an empty string to the database
I'm still learning GO so it is entirely possible my question needs more info.
The zero value for a string is an empty string, and you can't distinguish between the two.
If you are using the database/sql package, and need to distinguish between NULL and empty strings, consider using the sql.NullString type. It is a simple struct that keeps track of the NULL state:
type NullString struct {
String string
Valid bool // Valid is true if String is not NULL
}
You can scan into this type and use it as a query parameter, and the package will handle the NULL state for you.
Google's protocol buffers (https://code.google.com/p/goprotobuf/) use pointers to describe optional fields.
The generated objects provide GetFoo methods which take the pain away from testing for nil (a.GetFoo() returns an empty string if a.Foo is nil, otherwise it returns *a.Foo).
It introduces a nuisance when you want to write literal structs (in tests, for example), because &"something" is not valid syntax to generate a pointer to a string, so you need a helper function (see, for example, the source code of the protocol buffer library for proto.String).
// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string {
return &v
}
Overall, using pointers to represent optional fields is not without drawbacks, but it's certainly a viable design choice.
The standard database/sql package provides a NullString struct (members are just String string and Valid bool). To take care of some of the repetitive work of persistence, you could look at an object-relational manager like gorp.
I looked into whether there was some way to distinguish two kinds of empty string just out of curiosity, and couldn't find one. With []bytes, []byte{} == []byte(nil) currently returns false, but I'm not sure if the spec guarantees that to always remain true. In any case, it seems like the most practical thing to do is to go with the flow and use NullString.

Resources