Skip to content

Latest commit

 

History

History
210 lines (157 loc) · 5.96 KB

File metadata and controls

210 lines (157 loc) · 5.96 KB

#2.4 struct ##struct We can define new type of container of other properties or fields in Go like in other programming languages. For example, we can create a type called person to represent a person, this type has name and age. We call this kind of type as struct.

type person struct {
    	name string
    	age int
}

Look how easy it is to define a struct!

There are two fields.

  • name is a string used to store a person's name.
  • age is a int used to store a person's age.

Let's see how to use it.

type person struct {
    	name string
    	age int
}

var P person  // p is person type

P.name = "Astaxie"  // assign "Astaxie" to the filed 'name' of p
P.age = 25  // assign 25 to field 'age' of p
fmt.Printf("The person's name is %s\n", P.name)  // access field 'name' of p

There are three more ways to define struct.

  • Assign initial values by order

      P := person{"Tom", 25}
  • Use format field:value to initialize without order

      P := person{age:24, name:"Bob"}
  • Define a anonymous struct, then initialize it

      P := struct{name string; age int}{"Amy",18}

Let's see a complete example.

package main
import "fmt"

// define a new type
type person struct {
	name string
	age int
}

// compare age of two people, return the older person and differences of age
// struct is passed by value
func Older(p1, p2 person) (person, int) {
	if p1.age>p2.age {  
    	return p1, p1.age-p2.age
	}
	return p2, p2.age-p1.age
}

func main() {
	var tom person

	// initialization
	tom.name, tom.age = "Tom", 18

	// initialize two values by format "field:value"
	bob := person{age:25, name:"Bob"}

	// initialize two values with order
	paul := person{"Paul", 43}

	tb_Older, tb_diff := Older(tom, bob)
	tp_Older, tp_diff := Older(tom, paul)
	bp_Older, bp_diff := Older(bob, paul)

	fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)

	fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)

	fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)
}

###embedded fields in struct I just introduced you how to define a struct with fields name and type. In fact, Go support fields without name but types, we call these embedded fields.

When the embedded field is a struct, all the fields in that struct will be the fields in the new struct implicitly.

Let's see one example.

package main
import "fmt"

type Human struct {
	name string
	age int
	weight int
}

type Student struct {
	Human  // embedded field, it means Student struct includes all fields that Human has.
	speciality string
}

func main() {
	// initialize a student
	mark := Student{Human{"Mark", 25, 120}, "Computer Science"}

	// access fields
	fmt.Println("His name is ", mark.name)
	fmt.Println("His age is ", mark.age)
	fmt.Println("His weight is ", mark.weight)
	fmt.Println("His speciality is ", mark.speciality)
	// modify notes
	mark.speciality = "AI"
	fmt.Println("Mark changed his speciality")
	fmt.Println("His speciality is ", mark.speciality)
	// modify age
	fmt.Println("Mark become old")
	mark.age = 46
	fmt.Println("His age is", mark.age)
	// modify weight
	fmt.Println("Mark is not an athlet anymore")
	mark.weight += 60
	fmt.Println("His weight is", mark.weight)
}

Figure 2.7 Inheritance in Student and Human

We see that we access age and name in Student just like we access them in Human. This is how embedded field works. It is very cool, isn't it? Hold on, there is something cooler! You can even use Student to access Human this embedded field!

mark.Human = Human{"Marcus", 55, 220}
mark.Human.age -= 1

All the types can be used as embedded fields.

package main
import "fmt"

type Skills []string

type Human struct {
	name string
	age int
	weight int
}

type Student struct {
	Human  // struct as embedded field
	Skills // string slice as embedded field
	int    // built-in type as embedded field
	speciality string
}

func main() {
	// initialize Student Jane
	jane := Student{Human:Human{"Jane", 35, 100}, speciality:"Biology"}
	// access fields
	fmt.Println("Her name is ", jane.name)
	fmt.Println("Her age is ", jane.age)
	fmt.Println("Her weight is ", jane.weight)
	fmt.Println("Her speciality is ", jane.speciality)
	// modify value of skill field
	jane.Skills = []string{"anatomy"}
	fmt.Println("Her skills are ", jane.Skills)
	fmt.Println("She acquired two new ones ")
	jane.Skills = append(jane.Skills, "physics", "golang")
	fmt.Println("Her skills now are ", jane.Skills)
	// modify embedded field
	jane.int = 3
	fmt.Println("Her preferred number is", jane.int)
}

In above example we can see that all types can be embedded fields and we can use functions to operate them.

There is one more problem, if Human has a field called phone and Student has a filed with same name, what should we do?

Go use a very simple way to solve it. The outer fields get upper access levels, which means when you access student.phone, we will get the field called phone in student, not in the Human struct. This feature can be simply seen as overload of field.

package main
import "fmt"

type Human struct {
	name string
	age int
	phone string  // Human has phone field
}

type Employee struct {
	Human  // embedded field Human
	speciality string
	phone string  // phone in employee
}

func main() {
	Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
	fmt.Println("Bob's work phone is:", Bob.phone)
	// access phone field in Human
	fmt.Println("Bob's personal phone is:", Bob.Human.phone)
}

##Links