Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot use as type in assignment in go

Tags:

go

when I compile my code, I get the following error message, not sure why it happens. Can someone help me point why? Thank you in advance.

cannot use px.InitializePaxosInstance(val) (type PaxosInstance) as type *PaxosInstance in assignment

type Paxos struct {
    instance   map[int]*PaxosInstance
}    

type PaxosInstance struct {
    value        interface{}
    decided      bool
}    

func (px *Paxos) InitializePaxosInstance(val interface{}) PaxosInstance {
    return PaxosInstance {decided:false, value: val}
}

func (px *Paxos) PartAProcess(seq int, val interface{}) error {  
    px.instance[seq] = px.InitializePaxosInstance(val)
    return nil 

}

like image 221
vkosyj Avatar asked May 10 '17 19:05

vkosyj


3 Answers

Your map is expecting a pointer to a PaxosInstance (*PaxosInstance), but you are passing a struct value to it. Change your Initialize function to return a pointer.

func (px *Paxos) InitializePaxosInstance(val interface{}) *PaxosInstance {
    return &PaxosInstance {decided:false, value: val}
}

Now it returns a pointer. You can take the pointer of a variable using & and, should you need the struct value itself, dereference it again with *.

After a line like

x := &PaxosInstance{} 

or

p := PaxosInstance{}
x := &p

the value type of x is *PaxosInstance. And if you ever need to, you can dereference it back into a PaxosInstance struct value with

p = *x

You usually do not want to pass structs around as actual values, because Go is pass-by-value, which means it will copy the whole thing. Using struct values with maps and slices often results in logic errors because a copy is made should you iterate them or otherwise reference them except via index. It depends on your use-case, but your identifier Instance would infer that you would want to avoid duplications and such logic errors.

As for reading the compiler errors, you can see what it was telling you. The type PaxosInstance and type *PaxosInstance are not the same.

like image 84
RayfenWindspear Avatar answered Sep 20 '22 13:09

RayfenWindspear


The instance field within the Paxos struct is a map of integer keys to pointers to PaxosInstance structs.

When you call:

px.instance[seq] = px.InitializePaxosInstance(val)

You're attempting to assign a concrete (not pointer) PaxosInstance struct into an element of px.instance, which are pointers.

You can alleviate this by returning a pointer to a PaxosInstance in InitializePaxosInstance, like so:

func (px *Paxos) InitializePaxosInstance(val interface{}) *PaxosInstance {
    return &PaxosInstance{decided: false, value: val}
}

or you could modify the instance field within the Paxos struct to not be a map of pointers:

type Paxos struct {
    instance   map[int]PaxosInstance
}

Which option you choose is up to your use case.

like image 36
vase Avatar answered Sep 20 '22 13:09

vase


For anyone else pulling their hair out: check your imports.

Not sure when it started happening, but my Visual Studio Code + gopls setup will occasionally insert an import line that references my vendored dependencies path instead of the original import path. I usually won't catch this until I start polishing code for release, or an error like this one pops up.

In my case this caused two otherwise identical types to not compare equally. Once I fixed my imports this resolved the error.

like image 37
deoren Avatar answered Sep 20 '22 13:09

deoren