vkosyj
vkosyj

Reputation: 767

Cannot use as type in assignment in 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 
}

Upvotes: 23

Views: 72899

Answers (3)

RayfenWindspear
RayfenWindspear

Reputation: 6274

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.

Upvotes: 27

deoren
deoren

Reputation: 419

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.

Upvotes: 4

vase
vase

Reputation: 349

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.

Upvotes: 6

Related Questions