Polymorphic struct fields

(new to Go)

I’d like to create a struct field, which could hold pointers to two different types of structs. Example:

type Letter struct {
    ...
    Previous *Character // this is invalid, I don't have this type, it's just an example
}

type Punct struct {
    ...
    Previous *Character // this is invalid, I don't have this type, it's just an example
}

l1 := Letter{}
l2 := Letter{ Previous: &l1, }
p1 := Punct{ Previous: &l2, }
p2 := Punct{ Previous: &p1, }

The idea (simplified) is that a string consists of characters, which can either be letters or punctuation signs (no I cannot use rune type here, because each struct contains some other useful information I need to associate with each character). Each character has a reference to the previous character – thus the Previous field. As you can see, in each struct Previous should be assigned a pointer to either a struct of a different type or a struct of the same type.

But I’m not sure how to go about polymorphism here and which type should the Previous field be declared as. Interfaces don’t seem to make sense here, because they deal with methods, not field types. How would you go about this?

type Character sturct {
    Pre *Character
    Letter * Letter
    Punct * Punct
}
l1:=Character{Letter:&Letter{}}
l2:=Character{Pre:&l1,Letter:&Letter{}}
p1:=Character{Pre:&l2,Punct:&Punct{}}
p2:=Character{Pre:&p1,Punct:&Punct{}}

What should you focus on as a single element? As for whether this cell is a letter or a symbol, this is a property of this unit.

While it is possible to achieve the desired result through the interface, it may be necessary to call the assertion type.

Oh, thanks, this looks very obvious. Only problem is, it doesn’t quite scale and would require an additional field in the Character struct for each new struct I might decide to add. Wonder if there are other ways to achieve the same goal (I was hoping maybe my understanding of interfaces is simply lacking and there’s a solution involving interfaces).

Would you be able to briefly outline how would one do it with interfaces?

type Letter struct {
    Previous any
}

type Punct struct {
    Previous any
}

l1 := Letter{}
l2 := Letter{ Previous: &l1, }
p1 := Punct{ Previous: &l2, }
p2 := Punct{ Previous: &p1, }
// Like this, but to call, it has to be like this:
l,ok:=p1.Previous.(*Letter)
if ok{
}

This is simply a simple use of any to represent the interface, and will actually add some specific methods to avoid other structure type implementations and cause code confusion.

Right. I thought about using any, although that seemed a little broad. I don’t need to be particularly strict with my types, but, I suppose, it also wouldn’t hurt if I could understand how to achieve Go-style equivalent of polymorphism & inheritance in OOP, something like this (pseudo OOP-code):

class Character { ... }
class Letter extends Character {
    previous Character 
}
class Punct extends Character {
    previous Character
}
l1 = new Letter();
l2 = new Letter();
p1 = new Punct();
p2 = new Punct();
l2.previous = l1; 
p1.previous = l2;
p2.previous = p1;

This code restricts the previous field to instances of classes, that are descendants of Character.

type Character interface {
    Pre()Character
    ...
}
type Letter struct {
    Previous Character
}
func(l *Letter)Pre()Character{
    returen l.Previous
}

type Punct struct {
    Previous Character
}
func(p *Punct)Pre()Character{
    returen p.Previous
}

I don’t think you understand what an interface is.
Any is just a simple interface type, I’m just using any as an example. Actually, what you should do should be something like this.

You can use generics to achieve the same thing without any.

Generic? This is a good approach, but you also need to define an interface as a constraint for this scenario. If it’s just an example, I probably won’t use generics, but try to generalize and abstract into interfaces, which in my opinion is more extensible. Of course, specific issues have to be analyzed on a case-by-case basis, and this is just my personal opinion.