Is there a reason why I should create a struct using &StructName{} instead of Struct{}? I see many examples using the former syntax, even in the Effective Go Page but I really can not understand why.
Additional Notes:
I'm not sure whether I explained my problem well with these two approaches so let me refine my question.
I know that by using the & I will recieve a pointer instead of a value however I would like to know why would I use the &StructName{} instead of the StructName{}. For example, is there any benefits of using:
func NewJob(command string, logger *log.Logger) *Job {
return &Job{command, logger}
}
instead of:
func NewJob(command string, logger *log.Logger) Job {
return Job{command, logger}
}
Well, they will have different behavior. Essentially if you want to modify state using a method on a struct, then you will need a pointer, otherwise a value will be fine. Maybe an example will be better:
package main
import "fmt"
type test_struct struct {
Message string
}
func (t test_struct)Say (){
fmt.Println(t.Message)
}
func (t test_struct)Update(m string){
t.Message = m;
}
func (t * test_struct) SayP(){
fmt.Println(t.Message)
}
func (t* test_struct) UpdateP(m string) {
t.Message = m;
}
func main(){
ts := test_struct{}
ts.Message = "test";
ts.Say()
ts.Update("test2")
ts.Say() // will still output test
tsp := &test_struct{}
tsp.Message = "test"
tsp.SayP();
tsp.UpdateP("test2")
tsp.SayP() // will output test2
}
And you can run it here go playground
Assuming you know the general difference between a pointer and a value:
The first way allocates a struct and assigns a pointer to that allocated struct to the variable p1.
p1 := &StructName{}
The second way allocates a struct and assigns a value (the struct itself) to the variable s.
Then a pointer to that struct may be assigned to another variable (p2 in the following example).
s := StructName{}
p2 := &s
Related
I have following code:
package main
import (
"fmt"
)
func test(data interface{}) {
data = "123"
}
func main() {
t := "org"
test(&t)
fmt.Println(t)
e := 1
test(&e)
fmt.Println(e)
}
I tried to add pointer to *interface{} but it throws errors, how can I assign string "test" to t when I print it? right now t will be printed out as "org"
I am asking because I am not sure how I can use dynamic type here, for instance, josn.Unmarshal(data []byte, v interface{}) I used this function, and it can convert databyte to any type we want as long as we pass the reference.
I think you are expecting interface to be much more magic than it actually is.
Consider this variant of your program:
package main
import (
"fmt"
)
func test(p *string) {
s := "test"
p = &s
}
func main() {
t := "org"
test(&t)
fmt.Println(t)
}
Do you expect this to print test? If so, we have a bigger problem. :-) If not, why do you expect the version with p interface{} to change t when assigning directly to p?
If we change test to write through *p:
func test(p *string) {
*p = "test"
}
the program does print test, as you expected.
All that remains now is to handle the case when p is declared instead as data interface{}. As in bserdar's answer, you must first extract the underlying *string pointer from the interface object in data. You can then use that pointer to set main's variable t. You could do this with two steps:
func test(data interface{}) {
p := data.(*string)
*p = "test"
}
for instance, or you can do it all in one line.
You are setting the interface, not the underlying value. Instead you should do
func test(data interface{}){
*data.(*string) = "aaa"
}
That is, first get the underlying string pointer, then set the string pointed by it.
I have the following code and I want to use interfaces:
Current code:
import (
"github.com/dorzheh/deployer/ui/dialog_ui"
. "github.com/dorzheh/go-dialog"
)
// all methods in https://github.com/dorzheh/deployer/blob/master/ui/dialog_ui/dialog_ui.go#L28
type Pb struct {
sleep time.Duration
step int
}
type DialogUi struct {
*Dialog //The source is https://github.com/dorzheh/go-dialog/blob/master/dialog.go#L34
Pb *Pb
}
I am trying to implement interfaces this way:
import (
"testing"
// . "github.com/dorzheh/go-dialog"
//"github.com/dorzheh/deployer/ui/dialog_ui"
)
type PBifaceT interface {
Step() int
}
type TestDialogUiT struct {
Pb *PBifaceT
}
func TestUiValidateUser(t *testing.T) {
x := dialog_ui.TestDialogUiT{}
PbPb := ImplPBifaceT{}
x.Pb = PbPb
parentId := x.Pb.Step()
t.Logf(fmt.Sprintf("%v", parentId))
}
I've made a playground. As you can see it runs in the following error:
prog.go:23: cannot use PbPb (type ImplPBifaceT) as type *PBifaceT in assignment:
*PBifaceT is pointer to interface, not interface
prog.go:25: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)
I tried to convert them in this playground:
func NewD() *PBifaceT {
// var err error
var res =new(ImplPBifaceT)
return (*PBifaceT)(res)
}
func main() {
x := TestDialogUiT{}
x.Pb = NewD()
parentId := x.Pb.Step()
fmt.Sprintf("%v", parentId)
}
The issue:
prog.go:23: cannot convert res (type *ImplPBifaceT) to type *PBifaceT
prog.go:30: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)
Are you sure you need your PbĀ field as a *PBifaceT.
If you keep it as a
type TestDialogUiT struct {
Pb *PBifaceT
}
and you do
x := TestDialogUiT{}
PbPb := ImplPBifaceT{}
x.Pb = PBifaceT(PbPb)
parentId := x.Pb.Step()
fmt.Printf("%v", parentId)
It works properly..
Take a look at this playground and see if it can help.
I'd suggest you to take a look at this tutorial and this doc.
I'd suggest you also to read this SO answer which explains a bit of how you shouldn't want to use interface pointers.
Background: In Go you pass around a pointer to something because of two reasons:
1) You want because your struct is really large and you want to avoid copying
2) you need to because the calee wants to modify the original (this is typical for methods with a pointer receiver). Now an interface value is really tiny (just two words) so reason 1 to pass a pointer to an interface value does not apply.
Reason 2 does not apply in most cases as passing a pointer to an interface value will allow you to change the interface value itself, but most often you would like to modify the value stored inside the interface value. This value stored inside the interface value often is a pointer value which allows to change the value of a struct by calling methods on an interface value which wrapps a pointer to this struct. This sounds complicated but isn't: The novice Go programmer just doesn't use pointers to interfaces (as this won't do any good) and the experienced Go programmer doesn't use pointers to interfaces (as it won't do much good) unless he needs to modify an interface value, typically during reflection.
You can use Pb by link, you were just missing pointer reference while assigning.
package main
import (
"fmt"
)
type PBifaceT interface {
Step() int
}
type TestDialogUiT struct {
Pb PBifaceT
}
type ImplPBifaceT struct {
}
func (m *ImplPBifaceT) Step() int {
return 0
}
func main() {
x := TestDialogUiT{}
PbPb := &ImplPBifaceT{}
x.Pb = PbPb
parentId := x.Pb.Step()
fmt.Printf("%v", parentId)
}
Please refer this playground link: https://play.golang.org/p/N7quQFpYU0
Changes were at line 12, 17, 23 & 27.
Do not use pointer to interface unless you are sure that's what you want, see Pb *PBifaceT inside TestDialogUiT. If you change it to just Pb PBifaceT your playground link just works.
An interface is already a pointer.
TL;DR Somehow, I am appending a pointer to a list instead of the object within a for loop of objects so at the end the entire slice is composed of the same object multiple times. I just don't know how to fix that.
The Long Way
I am still having a super hard time trying to figure out pointers in go. I posted a question yesterday and got some help but now I am stuck on a slightly different issue in the same piece of code.
I am working with gocql and cqlr go packages to try and bit a small object mapper for my Cassandra queries. Essentially the problem I am having is I am appending what appears to be a pointer to an object, not a new instance of the obj to the array. How do I fix that? I have tried adding & and * in front of value but that doesn't seem to work. How do I fix these? The bind function needs an & according to their docs.
Code
type Query struct {
query string
values interface{}
attempts int
maxAttempts int
structType reflect.Type
}
func (query Query) RetryingQuery() (results []interface{}) {
var q *gocql.Query
if query.values != nil {
q = c.Session.Query(query.query, query.values)
} else {
q = c.Session.Query(query.query)
}
bindQuery := cqlr.BindQuery(q)
value := reflect.New(query.structType).Interface()
for bindQuery.Scan(value) {
fmt.Println(value)
results = append(results, value)
}
return
}
The docs ask for var value type then in bind you would pass &value. I quoted the docs below.
var t Tweet
var s []Tweet
for b.Scan(&t) {
// Application specific code goes here
append(s, t)
}
The issue is I cannot directly go var value query.structType to define its type then pass the reference of that to bindQuery.Scan().
What is printed
&{result1 x86_64 24 3.2.0-74-generic Linux}
&{result2 x86_64 24 3.19.0-25-generic Linux}
&{result3 x86_64 4 3.13.0-48-generic Linux}
&{result4 x86_64 2 3.13.0-62-generic Linux}
&{result5 x86_64 4 3.13.0-48-generic Linux}
What is in the slice
Spoiler, it is result5 repeated over and over. I understand that I am just appending the pointer to same object to the list and that every loop iteration the object is changed and that changes all the results in the slice to that new object. I just don't know how to fix it.
[{"hostname":"result5","machine":"x86_64","num_cpus":4,"release":"3.13.0-48-generic","sysname":"Linux"},{"hostname":"result5","machine":"x86_64","num_cpus":4,"release":"3.13.0-48-generic","sysname":"Linux"},{"hostname":"result5","machine":"x86_64","num_cpus":4,"release":"3.13.0-48-generic","sysname":"Linux"},{"hostname":"result5","machine":"x86_64","num_cpus":4,"release":"3.13.0-48-generic","sysname":"Linux"},{"hostname":"result5","machine":"x86_64","num_cpus":4,"release":"3.13.0-48-generic","sysname":"Linux"}]
Well I can at least tell you what you're doing. bindQuery takes a pointer. It changes the value stored at the address.
What you're essentially doing is this:
package main
import "fmt"
func main() {
var q int
myInts := make([]*int, 0, 5)
for i := 0; i < 5; i++ {
q = i
fmt.Printf("%d ", q)
myInts = append(myInts, &q)
}
fmt.Printf("\n")
for _, value := range myInts {
fmt.Printf("%d ", *value)
}
fmt.Printf("\n")
fmt.Println(myInts)
}
Which, as you can probably guess, gives you this:
0 1 2 3 4
4 4 4 4 4
[0x104382e0 0x104382e0 0x104382e0 0x104382e0 0x104382e0]
Things get a little more confusing with reflect. You can get your type as an interface, but that is it (unless you want to play with unsafe). An interface, in simple terms, contains a pointer to the original type underneath (and some other stuff). So in your function you are passing a pointer (and some other stuff). Then you're appending the pointer. It might be nice just to get concrete and type switch your interface. I assume you know what types it could be. In which case you'd have to have something along these lines:
package main
import (
"fmt"
"reflect"
)
type foo struct {
fooval string
}
type bar struct {
barval string
}
func main() {
f1 := foo{"hi"}
f2 := &foo{"hi"}
b1 := bar{"bye"}
b2 := &bar{"bye"}
doSomething(f1)
doSomething(f2)
doSomething(b1)
doSomething(b2)
}
func doSomething(i interface{}) {
n := reflect.TypeOf(i)
// get a new one
newn := reflect.New(n).Interface()
// find out what we got and handle each case
switch t := newn.(type) {
case **foo:
*t = &foo{"hi!"}
fmt.Printf("It was a **foo, here is the address %p and here is the value %v\n", *t, **t)
case **bar:
*t = &bar{"bye :("}
fmt.Printf("It was a **bar, here is the address %p and here is the value %v\n", *t, **t)
case *foo:
t = &foo{"hey!"}
fmt.Printf("It was a *foo, here is the address %p and here is the value %v\n", t, *t)
case *bar:
t = &bar{"ahh!"}
fmt.Printf("It was a *bar, here is the address %p and here is the value %v\n", t, *t)
default:
panic("AHHHH")
}
}
You could also just keep calling value = reflect.New(query.structType).Interface() inside of the loop which will give you new interfaces every time. Reassigning value after every append. Last time through the loop would make one extra though..
I just need a pointer to time.Time, so the code below seems invalid:
./c.go:5: cannot take the address of time.Now()
I just wonder why? Is there any way to do that except to do assignment to a variable first and take the pointer of the variable?
package main
import "time"
func main() {
_ = &time.Now()
}
The probably unsatisfying answer is "you can't do it because the spec says so." The spec says that to use & on something it has to be addressable or a compound literal, and to be addressable it has to be "a variable, pointer indirection, or slice indexing operation; or a a field selector of an addressable struct operand; or an array indexing operation of an addressable array." Function calls and method calls are definitely not on the list.
Practically speaking, it's probably because the return value of a function may not have a usable address; it may be in a register (in which case it's definitely not addressable) or on the stack (in which case it has an address, but one that won't be valid if it's put in a pointer that escapes the current scope. To guarantee addressability, Go would have to do pretty much the exact equivalent of assigning it to a variable. But Go is the kind of language that figures that if it's going to allocate storage for a variable it's going to be because you said to, not because the compiler magically decided to. So it doesn't make the result of a function addressable.
Or I could be over-thinking it and they simply didn't want to have a special case for functions that return one value versus functions that return multiple :)
You can't directly take the address of a function call (or more precisely the return value(s) of the function) as described by hobbs.
There is another way but it is ugly:
p := &[]time.Time{time.Now()}[0]
fmt.Printf("%T %p\n%v", p, p, *p)
Output (Go Playground):
*time.Time 0x10438180
2009-11-10 23:00:00 +0000 UTC
What happens here is a struct is created with a literal, containing one element (the return value of time.Now()), the slice is indexed (0th element) and the address of the 0th element is taken.
So rather just use a local variable:
t := time.Now()
p := &t
Or a helper function:
func ptr(t time.Time) *time.Time {
return &t
}
p := ptr(time.Now())
Which can also be a one-liner anonymous function:
p := func() *time.Time { t := time.Now(); return &t }()
Or as an alternative:
p := func(t time.Time) *time.Time { return &t }(time.Now())
For even more alternatives, see:
How do I do a literal *int64 in Go?
Also see related question: How can I store reference to the result of an operation in Go?
Fortunately, generics now offer quite a clean solution by defining a function only one time, that can be used on any type:
package main
func ptr[T any](x T) *T {
return &x
}
func main() {
print(ptr("foo"))
print(ptr(42))
}
Playground: https://go.dev/play/p/TgpEPKjpXX7
However, this will work only starting from Golang 1.18. For previous versions, you'll need a function for each type, as other answers suggested.
If you are having this trouble with a function you wrote, change your function to return a pointer. Even though you can't take the address of a return value, you can dereference a return value, so it will be suitable whether you want the pointer or the object.
func Add(x, y int) *int {
tmp := x + y
return &tmp
}
func main() {
fmt.Println("I want the pointer: ", Add(3, 4))
fmt.Println("I want the object: ", *Add(3, 4))
}
https://play.golang.org/p/RogRZDNGdmY
I wrote a simple program using the Go Playground at golang.org.
The output is obviously:
second test
first test
Is there a way to edit the map value in place? I know I can't take the andress of a.Things[key]. So, is setting a.Things[key] = firstTest the only way to do it? Maybe with a function ChangeThing(key string, value string)?
You could do it by making the values of your map pointers to another struct.
http://play.golang.org/p/UouwDGuVpi
package main
import "fmt"
type A struct {
Things map[string]*str
}
type str struct {
s string
}
func (a A) ThingWithKey(key string) *str {
return a.Things[key]
}
func main() {
variable := A{}
variable.Things = make(map[string]*str)
variable.Things["first"] = &str{s:"first test"}
firstTest := variable.ThingWithKey("first")
firstTest.s = "second test"
fmt.Println(firstTest.s)
fmt.Println(variable.ThingWithKey("first").s)
}
You can use a pointer as the map value http://play.golang.org/p/BCsmhevGMX