Go Structs and Methods
Now it’s time to review OOP in Go.
Go OOP
Go only supports encapsulation, but it doesn’t support inheritance or polymorphism, which is not necessarily a bad thing, as it removes unnecessary confugions.
There’s no class
in Go, there’s on struct
.
Define a struct
Let’s declare a very common data structure treeNode
with struct. It should have the following elements:
- value
- left, right, which are pointers
1 | type treeNode struct { |
To create a treeNode type of data
1 | func main(){ |
Here root
is a treeNode type data with value of 0, left and right pointing to nil
. The outputs will be:
1 | {0 <nil> <nil>} |
To assign values, left and right to the root
treeNode,
1 | root = treeNode{value: 3} |
Note left
and right
are pointers, so they need to use &
to get the node address.
We could also create treeNode with new
method.
1 | root.right.left = new(treeNode) |
See how simple and elegant to use Go pointers, we could use .
directly after a pointer pointing to another pointer.
- Use
.
to access members (which can be an address, a value or the struct itself)
Slices of Structs
We can build a slice of structs
1 | nodes := []treeNode{ |
The outputs will be:
1 | [{3 <nil> <nil>} {0 <nil> <nil>} {6 <nil> 0xc0000a6018}] |
Methods
Go doesn’t have generator functions. We could use factory functions alternatively as generator functions.
1 | func createNode(value int) *treeNode { |
We could call the createNode
function
1 | func main() { |
The outputs will be:
1 | {3 0xc0000a6018 0xc0000a6030} |
Go has automatic garbage collector, so we don’t need to know if the struct
is on stack or heap.
Define struct method
Unlike other OOP languages, in Go the struct method is defined outside the struct block.
1 | func (node treeNode) print(){ |
We need to pass node treeNode
as the parameter, which is similar to self
in Python or this
in Java.
To invoke it, we can just call directly:
1 | root.print() |
The output will be
1 | 3 |
We can define a “setter”
1 | func (node treeNode) setValue(value int){ |
Then invoke it:
1 | root.right.left.print() |
The outputs will be:
1 | 3 |
Because Go functions passes value not address, so the “setter” won’t work as expected. Instead, refactor it as
1 | func (node *treeNode) setValue(value int){ |
Re-invoking the functions, the outputs will be:
1 | 3 |
In-Order Traverse
To traverse the tree:
1 | func (node *treeNode) traverse(){ |
Invoke traverse
in main
, we will get the outputs:
1 | 0 |
Passing-Value vs. Passing-Pointer
- If we want to change the content, we must pass pointers
- If the struct is too big, consider passing pointers as well
- Be consistent, if passing pointers, keep passing pointers