Slice and array are good for storing collection of data which is of same type. What if our data is made up of smaller types which are different? This is where struct comes in handy.A struct is a type that contains named fields. Struct is a value that is constructed out of other values of many different types.
Slices and maps are used to store collection of similar data where as struct is used to groups together zero or more named values of arbitrary types as a single entity. Grouping together data of different types, that's where struct is useful.
A simple struct can be constructed using struct
keyword as
struct {field type}
main.govar person struct {name stringage int}
name
and age
are called fields of struct.
Generally, we will use multiple instance of struct in code. It is very common define struct as user defined type using type
keyword for reuse.
main.gotype person struct {name stringage int}var p1 personvar p2 person
now person
is a user defined struct
type. p1
and p2
variables are both of type person
.
Declaring a variable of a particular struct type creates a struct. There is no explicit call required to any other function.
main.govar p1 personvar p2 personfmt.Println(p1)fmt.Println(p2)
Struct fields are accessed using dot operator .
This can be used to read as well as write to struct fields.
main.gop1.name = "Joey"p1.age = 30fmt.Println(p1)
When a struct is declared, it gets initialized to zero values for its all the fields.
main.gotype show struct {name stringprice float64isAvailable boolrating int}var s showfmt.Printf("%#v\n", s)// output// main.show{name:"", price:0, isAvailable:false, rating:0}
We can use struct literals to declare and initialize struct with initial value instead of zero value. We can define person struct type using struct literal as
main.govar p3 person = person{name: "Chandler",age: 32,}fmt.Printf("%#v\n", p3)
Two structs of same type are comparable if and only if all the fields of the struct are comparable using ==.
main.govar p4 person = person{name: "Chandler",age: 32,}var p5 person = person{name: "Joey",age: 30,}fmt.Println("are p4 and p5 equal? ==>", p4 == p5)
Like we can use data types like integers ,floats and strings as fields for a struct, we can also user another struct as field for building new structs. This is useful for reusing already created user defined types.
main.gotype human struct {name stringage int}​type superHuman struct {human humanpower string}​superman := superHuman{human: human{name: "Clark Kent",age: 30,},power: "Flying",}​fmt.Printf("%#v\n", superman)// output// main.superHuman{human:main.human{name:"Clark Kent", age:30}, power:"Flying"}
Note that if we need to access name of superman we need to use superman.human.name
main.gofmt.Println(superman.human .name)
What if we wish to use superman.name
instead of superman.human.name
in above code? Go supports this by providing type embedding. An inner struct that is stored within an outer struct using an anonymous field is said to be embedded within the outer struct.
We are embedding human
type inside superHero
type. There is no named field inside superHero
to which we are assigning human
type. Outside struct literal, we can access fields of human
type directly as if these fields exists on superHero
. This is called type promotion.
main.gotype superHero struct {livesSaved inthuman // embedding type}batman := superHero{}ironman := superHero{livesSaved: 100000,human: human{name: "Tony",age: 40,},}​batman.name = "Bruce" // accessing embedded type's fieldbatman.age = 50 // accessing embedded type's fieldbatman.livesSaved = 100​fmt.Printf("%#v\n", batman)fmt.Printf("%#v\n", ironman)