Structure consists of different types of values.
The syntax is following:
type STRUCT_NAME struct {
FIELD_NAME DATA_TYPE
...
}
If the name of a structure starts with a capital letter, it is exported to the outside of the package.
Structure Declaration
var testStruct struct {
numField float64
strField string
boolField bool
}
fmt.Println(testStruct)
// {0 false}]
testStruct.numField = 7
testStruct.strField = "Hi"
testStruct.boolField = true
fmt.Println(testStruct)
// {7 Hi true}
The zero value depends on the type of the field.
If you access the field in the Structure, you should use a dot(.).
Type Definition
You can make user-defined types using type definition.
package main
import "fmt"
type student struct {
name string
score int
}
func main() {
var hoya student
hoya.name = "hoya"
hoya.score = 98
fmt.Println(hoya)
// {hoya 98}
var park student
park.name = "park"
park.score = 87
fmt.Println(park)
// {park 87}
}
You can also use Structure as a parameter type or return type of the function.
Structure Literal
hoya := student{"hoya", 98}
fmt.Println(hoya)
// {hoya 98}
park := student{name: "park"}
fmt.Println(park)
// {park 0}
kim := student{score: 97}
fmt.Println(kim)
// { 97}
You can omit some fields, and it will be filled with initial values of its type.
Structure with Pointer
This example shows you how to use a pointer variable with Structure.
var hoya student
hoya.name = "hoya"
hoya.score = 98
var p *student = &hoya
fmt.Println((*p).name, p.score)
// hoya 98
Go is a pass-by-value language.
So you need to use a pointer if you want to change the argument's value inside the function.
func addScore(st *student) {
st.score++
}
func main() {
var hoya student
hoya.name = "hoya"
hoya.score = 90
addScore(&hoya)
fmt.Println(hoya)
}
// {hoya 91}
Structure Nesting
Structure can be nested.
type point struct {
x int
y int
}
type worldMap struct {
objA point
objB point
}
func main() {
locationA := point{x: 5, y: 7}
locationB := point{x: 3, y: 6}
currentMap := worldMap{objA: locationA, objB: locationB}
fmt.Println(currentMap)
// {{5 7} {3 6}}
currentMap.objA.y = 9
currentMap.objB.x = 1
fmt.Println(currentMap)
// {{5 9} {1 6}}
}
Anonymous Field
Anonymous field means a field in a structure that does not have a name but only a type.
type point struct {
x int
y int
}
type shop struct {
name string
point
}
func main() {
barberShop := shop{name: "pop's barber shop"}
barberShop.point.x = 3
barberShop.point.y = 5
fmt.Println(barberShop)
// {pop's barber shop {3 5}}
barberShop.x = 7
barberShop.y = 9
fmt.Println(barberShop)
// {pop's barber shop {7 9}}
}
In the first case, we can access the anonymous field with the name of the type.
It is said that the internal Structure declared as an anonymous field of the external Structure has been embedded into the external Structure.
The fields of embedded Structure is promoted to the external Structure.
In other words, we can access the fields of internal Structure like the fields of external Structure.
But of course, the field name should be unique.
Memory Alignment
Go's structure has padding for memory alignment the same as C.
var struct1 struct {
field1 int64
field2 float64
}
var struct2 struct {
field1 int32
field2 float64
}
fmt.Println(unsafe.Sizeof(struct1)) // 16
fmt.Println(unsafe.Sizeof(struct2)) // 16
The actual size is 16 and 12, but the result was both 16.
Because my machine is a 64 bits machine, so the memory bus width is 8 bytes and it is aligned by 8 bytes.
Therefore, the int32 field is added 4 bytes padding.
If my machine is a 32 bits machine, the result would be 16 and 12.
Encapsulation
Encapsulation is used when we protect the fields of the structure.
Let's make our own Date package.
This file should be located in the date folder of the workspace of Go.
date/date.go
package date
// Date structure
type Date struct {
year int
month int
day int
}
Setter Method
Packages that want to set the protected fields of the structure has to use the setter method.
func (d *Date) SetYear(year int) error {
if year < 1 {
return errors.New("invalid year")
}
d.year = year
return nil
}
func (d *Date) SetMonth(month int) error {
if month < 1 || month > 12 {
return errors.New("invalid month")
}
d.month = month
return nil
}
func (d *Date) SetDay(day int) error {
if day < 1 || day > 31 {
return errors.New("invalid day")
}
d.day = day
return nil
}
Getter Method
Packages that want to access the protected fields of the structure has to use the getter method.
func (d *Date) Year() int {
return d.year
}
func (d *Date) Month() int {
return d.month
}
func (d *Date) Day() int {
return d.day
}
Usage Getter and Setter
You can't access the fields of the Date structure.
package main
import (
"date"
"fmt"
"log"
)
func main() {
today := date.Date{}
err := today.SetYear(2020)
if err != nil {
log.Fatal(err)
}
err = today.SetMonth(11)
if err != nil {
log.Fatal(err)
}
err = today.SetDay(11)
if err != nil {
log.Fatal(err)
}
fmt.Println(today.Year(), today.Month(), today.Day())
// 2020 11 11
}
Encapsulation
Like the above example, hiding data in one area of a program from another code is called encapsulation.
Go usually exposes the field to the outside and approaches it directly.
However, encapsulation is used when validation of values in a structure field is required.
Embedding
We can embed other types in the structure types.
Let's make two files.
embedding/embedded.go
package embedding
// Embedded structure.
type Embedded struct {
value int
State bool
}
func (e *Embedded) SetValue(value int) {
e.value = value
}
embedding/container.go
package embedding
// Container structure.
type Container struct {
name string
Embedded
}
func (c *Container) SetName(name string) {
c.name = name
}
In the above example, the Container structure contains the Embedded structure.
Now, use these structures.
test.go
package main
import (
"embedding"
"fmt"
)
func main() {
test := embedding.Container{}
// test.name = "Container" // Error
test.Embedded.State = true
// test.Embedded.value = 1 // Error
fmt.Println(test)
// { {0 true}}
test.SetName("container")
test.Embedded.SetValue(2)
fmt.Println(test)
// {container {2 true}}
test.State = false
test.SetValue(3)
fmt.Println(test)
// {container {3 false}}
}
First, you can access only exposed fields of a structure.
Second, you can access exposed embedded methods.
Third, exposed embedded methods can be promoted.
'Go' 카테고리의 다른 글
[Go] Rune and String (0) | 2021.10.16 |
---|---|
[Go] Pointer (0) | 2021.10.11 |
[Go] Array (0) | 2021.10.10 |
[Go] Control Flow (0) | 2021.10.10 |
[Go] Constant (0) | 2021.10.05 |
댓글