Go language has no concept of "class" does not support the "class" of inheritance and other object-oriented concepts. Go coupled with the interface language of object-oriented higher than the expandability and flexibility through the embedded structure.
Type alias, and custom types
Custom Types
There are some basic data types, such as the Go language string
, 整型
, 浮点型
, 布尔
and other data types, you can use the Go language type
keyword to define a custom type.
Custom type is to define a new type. We can be defined based on the built-in basic types can also be defined by struct. E.g:
//将MyInt定义为int类型
type MyInt int
By Type
definition of the keyword, MyInt
it is a new type that has int
properties.
Type alias
Type alias is Go1.9
the new version features added.
Type alias provisions: TypeAlias only Type an alias, in essence, TypeAlias and Type are the same type. Like a child has a child nickname, pet name, the scientific name for school, English teacher and give him the English name, but these names all refer to him personally.
type TypeAlias = Type
We've seen before rune
, and byte
is the type alias, they are defined as follows:
type byte = uint8
type rune = int32
The difference between type definitions and type aliases
Type alias type definition is only one difference between the surface of the equal sign, we have to understand the difference between them by following the code.
//类型定义
type NewInt int
//类型别名
type MyInt = int
func main() {
var a NewInt
var b MyInt
fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
fmt.Printf("type of b:%T\n", b) //type of b:int
}
The results show that the type is a main.NewInt
showing of the main package defined NewInt
type. b type is int
. MyInt
Type in the code will only exist when there is not compiled MyInt
types.
Structure
Go underlying data type can be expressed in the language of some basic properties of things, but when we want to express all or part of a property of things, then this time the single basic data types obviously can not meet the demand, Go language provides a kinds of custom data types, can encapsulate a plurality of basic data types, data type called this structure, the English name struct
. That is, we can struct
define your own type of.
Go through language struct
to implement object-oriented.
The definition of the structure
Use type
and struct
keyword to define the structure, the specific code format is as follows:
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
among them:
- Name Type: identifies the name of the custom structure, can not be repeated in the same package.
- Field Name: Indicates the structure field name. Struct field names must be unique.
- Field Type: indicates the type of the specific structure of the field.
For example, we define a Person
(human) body structure, as follows:
type person struct {
name string
city string
age int8
}
The same type of field can also be written on one line,
type person1 struct {
name, city string
age int8
}
So we have a person
custom type, it has name
, city
, age
three fields, respectively name, city and age. We use this person
structure can easily represent and store personal information in the program.
Built into the language used to describe the basic data type is a value, and the structure is used to describe a set of values. For example, a person has a name, age and city of residence, etc., it is essentially a polymeric type of data
Examples of structure
Only when the structure is instantiated, it will actually allocate memory. That is, the field must be instantiated in order to use the structure.
Itself is a type of structure, we can use the built-in types like declare var
keyword to declare a structure type.
var 结构体实例 结构体类型
The basic instantiation
for example:
type person struct {
name string
city string
age int8
}
func main() {
var p1 person
p1.name = "沙河娜扎"
p1.city = "北京"
p1.age = 18
fmt.Printf("p1=%v\n", p1) //p1={沙河娜扎 北京 18}
fmt.Printf("p1=%#v\n", p1) //p1=main.person{name:"沙河娜扎", city:"北京", age:18}
}
We .
fields (member variables) to access structure, for example, p1.name
and p1.age
so on.
Anonymous structure
In the definition of some temporary data structures, etc. may also be used anonymously scene structure.
package main
import (
"fmt"
)
func main() {
var user struct{Name string; Age int}
user.Name = "小王子"
user.Age = 18
fmt.Printf("%#v\n", user)
}
Create a pointer type structure
We can also use new
instantiated keyword structure, get the address of the structure. Format is as follows:
var p2 = new(person)
fmt.Printf("%T\n", p2) //*main.person
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"", city:"", age:0}
From the result we can see that the printed p2
a structure pointer.
Note that the support structure pointer directly in the Go language .
to member access structure.
var p2 = new(person)
p2.name = "小王子"
p2.age = 28
p2.city = "上海"
fmt.Printf("p2=%#v\n", p2) //p2=&main.person{name:"小王子", city:"上海", age:28}
Taking the address structure of the instantiated
Use &
of the body structure fetch address operation is equivalent to a type of the structural new
example of operation.
p3 := &person{}
fmt.Printf("%T\n", p3) //*main.person
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}
p3.name = "七米"
p3.age = 30
p3.city = "成都"
fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"七米", city:"成都", age:30}
p3.name = "七米"
In fact, the bottom is (*p3).name = "七米"
, this is the Go language syntactic sugar to help us achieve.
Structure initialization
The structure has not been initialized, its member variables are zero value corresponding to its type.
type person struct {
name string
city string
age int8
}
func main() {
var p4 person
fmt.Printf("p4=%#v\n", p4) //p4=main.person{name:"", city:"", age:0}
}
Use key-value pairs to initialize
When using the structure of the key-value is initialized, the key corresponding to the field structure, the initial value of the field should be.
p5 := person{
name: "小王子",
city: "北京",
age: 18,
}
fmt.Printf("p5=%#v\n", p5) //p5=main.person{name:"小王子", city:"北京", age:18}
It may also be key to initialize pointers to structures, for example:
p6 := &person{
name: "小王子",
city: "北京",
age: 18,
}
fmt.Printf("p6=%#v\n", p6) //p6=&main.person{name:"小王子", city:"北京", age:18}
When some fields with no initial value, the field can not write. In this case, the value field does not specify an initial value is the zero value of the field type.
p7 := &person{
city: "北京",
}
fmt.Printf("p7=%#v\n", p7) //p7=&main.person{name:"", city:"北京", age:0}
Use the list of initialization values
Initialization structure can be abbreviated, which is initialized when the key is not to write, write directly to the value of:
p8 := &person{
"沙河娜扎",
"北京",
28,
}
fmt.Printf("p8=%#v\n", p8) //p8=&main.person{name:"沙河娜扎", city:"北京", age:28}
With this initialization format, you need to pay attention to:
- All fields must be initialized structure.
- Filling sequence initial value must match the field order in the declaration of the structure.
- The method can not mix and key initialization method.
Structure of the memory layout
Structure occupies a contiguous memory.
type test struct {
a int8
b int8
c int8
d int8
}
n := test{
1, 2, 3, 4,
}
fmt.Printf("n.a %p\n", &n.a)
fmt.Printf("n.b %p\n", &n.b)
fmt.Printf("n.c %p\n", &n.c)
fmt.Printf("n.d %p\n", &n.d)
Output:
n.a 0xc0000a0060
n.b 0xc0000a0061
n.c 0xc0000a0062
n.d 0xc0000a0063
[] Advanced knowledge about the Go language Recommended reading memory alignment: alignment in Go right memory
Interview questions
What Will the results of the following code?
type student struct {
name string
age int
}
func main() {
m := make(map[string]*student)
stus := []student{
{name: "小王子", age: 18},
{name: "娜扎", age: 23},
{name: "大王八", age: 9000},
}
for _, stu := range stus {
m[stu.name] = &stu
}
for k, v := range m {
fmt.Println(k, "=>", v.name)
}
}
Constructor
Go structure of language has no constructor, we own realization. For example, the code below on the realization of a person
constructor. Because struct
are value types, if the structure is more complex, copies the value of the performance overhead will be relatively large, so that the constructor returns a pointer to a structure type.
func newPerson(name, city string, age int8) *person {
return &person{
name: name,
city: city,
age: age,
}
}
Call the constructor
p9 := newPerson("张三", "沙河", 90)
fmt.Printf("%#v\n", p9) //&main.person{name:"张三", city:"沙河", age:90}
Methods & Recipients
Go languages 方法(Method)
is an action to a particular type of variable function. This particular type of variable called 接收者(Receiver)
. The concept is similar to the recipient in other languages this
or self
.
The method is defined in the following format:
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}
among them,
- Recipient variables: Parameter variable names when naming the recipient of the official recommended to use the name of the recipient of the first type lowercase letters, instead
self
,this
named the like. For example,Person
the type of a variable should be named recipientp
,Connector
the type of receiver should be named variablec
like. - Type receiver: the receiver type and similar parameters, may be a pointer and non-pointer type type.
- Method name, parameter list, return parameters: same as the specific format of the function definition.
for example:
//Person 结构体
type Person struct {
name string
age int8
}
//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
return &Person{
name: name,
age: age,
}
}
//Dream Person做梦的方法
func (p Person) Dream() {
fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}
func main() {
p1 := NewPerson("小王子", 25)
p1.Dream()
}
The method and the difference function is not a function of any type, belonging to a specific type of method.
Pointer type recipient
Pointer type receiver a pointer to a structure of the composition, due to the characteristics of the pointer, pointer modify any recipient member variables when calling the method, after the method, the modifications are effective. In this way it is very close to other object-oriented languages is this
or self
. For example, we Person
add a SetAge
method to modify the age instance variable.
// SetAge 设置p的年龄
// 使用指针接收者
func (p *Person) SetAge(newAge int8) {
p.age = newAge
}
This method is called:
func main() {
p1 := NewPerson("小王子", 25)
fmt.Println(p1.age) // 25
p1.SetAge(30)
fmt.Println(p1.age) // 30
}
Value type of recipient
When the method to value the role of recipient types, Go language code that will run when the value of the recipient's copy. In the method you can get the value of the type of the recipient of the recipient member values, but only for a copy of the modification operation, the recipient can not modify the variable itself.
// SetAge2 设置p的年龄
// 使用值接收者
func (p Person) SetAge2(newAge int8) {
p.age = newAge
}
func main() {
p1 := NewPerson("小王子", 25)
p1.Dream()
fmt.Println(p1.age) // 25
p1.SetAge2(30) // (*p1).SetAge2(30)
fmt.Println(p1.age) // 25
}
When should you use a pointer type receiver
- You need to modify the value of the recipient
- The recipient is a copy of the cost of a relatively large large object
- Ensure consistency, if there is a method using a pointer receiver, so other methods should use the pointer recipient.
Add any type of method
In the Go language, type the recipient may be of any type, not just the structure, can have any type of method. For example, we built based on int
the use of type keyword type can define new custom type, and then add a method to our custom type.
//MyInt 将int定义为自定义MyInt类型
type MyInt int
//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
fmt.Println("Hello, 我是一个int。")
}
func main() {
var m1 MyInt
m1.SayHello() //Hello, 我是一个int。
m1 = 100
fmt.Printf("%#v %T\n", m1, m1) //100 main.MyInt
}
Note: non-native types can not be defined method, which means that we can not give other package type definition method.
Anonymous field structure
Structure does not allow its members to field the field name in the statement but only the type, not the name of this field is called an anonymous field.
//Person 结构体Person类型
type Person struct {
string
int
}
func main() {
p1 := Person{
"小王子",
18,
}
fmt.Printf("%#v\n", p1) //main.Person{string:"北京", int:18}
fmt.Println(p1.string, p1.int) //北京 18
}
Anonymous fields default to the type name as the field name, the structure required field names must be unique, so a structure of the same anonymous type of field can only have one.
Nesting structure
A structural body may contain a nested structure or another structure pointer.
//Address 地址结构体
type Address struct {
Province string
City string
}
//User 用户结构体
type User struct {
Name string
Gender string
Address Address
}
func main() {
user1 := User{
Name: "小王子",
Gender: "男",
Address: Address{
Province: "山东",
City: "威海",
},
}
fmt.Printf("user1=%#v\n", user1)//user1=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}
Anonymous nested structure
//Address 地址结构体
type Address struct {
Province string
City string
}
//User 用户结构体
type User struct {
Name string
Gender string
Address //匿名结构体
}
func main() {
var user2 User
user2.Name = "小王子"
user2.Gender = "男"
user2.Address.Province = "山东" //通过匿名结构体.字段名访问
user2.City = "威海" //直接访问匿名结构体的字段名
fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}
We will first find the field in the structure when accessing structure members, can not find the look to go anonymous structure.
Field name conflict nested structure
Internal nested structure which may exist in the same field name. This time in order to avoid ambiguity need to specify the specific field of embedded structure.
//Address 地址结构体
type Address struct {
Province string
City string
CreateTime string
}
//Email 邮箱结构体
type Email struct {
Account string
CreateTime string
}
//User 用户结构体
type User struct {
Name string
Gender string
Address
Email
}
func main() {
var user3 User
user3.Name = "沙河娜扎"
user3.Gender = "男"
// user3.CreateTime = "2019" //ambiguous selector user3.CreateTime
user3.Address.CreateTime = "2000" //指定Address结构体中的CreateTime
user3.Email.CreateTime = "2000" //指定Email结构体中的CreateTime
}
Structure "inheritance"
Go language used in structures can also be implemented in other programming languages, object-oriented inheritance.
//Animal 动物
type Animal struct {
name string
}
func (a *Animal) move() {
fmt.Printf("%s会动!\n", a.name)
}
//Dog 狗
type Dog struct {
Feet int8
*Animal //通过嵌套匿名结构体实现继承
}
func (d *Dog) wang() {
fmt.Printf("%s会汪汪汪~\n", d.name)
}
func main() {
d1 := &Dog{
Feet: 4,
Animal: &Animal{ //注意嵌套的是结构体指针
name: "乐乐",
},
}
d1.wang() //乐乐会汪汪汪~
d1.move() //乐乐会动!
}
Visibility field structure
At the beginning of the field structure represented publicly accessible uppercase, lowercase represents private (defined only in the current packet structure can be accessed).
Sequence and structure of JSON
JSON (JavaScript Object Notation) is a lightweight data interchange format. Easy to read and write. It is easy for machines to parse and generate. JSON key-value pair is used to save a way JS object, key / value pair combination keys and double quotes EDITORIAL ""
wrapped, colon :
-separated, and then followed by value; English key between a plurality of ,
separated .
//Student 学生
type Student struct {
ID int
Gender string
Name string
}
//Class 班级
type Class struct {
Title string
Students []*Student
}
func main() {
c := &Class{
Title: "101",
Students: make([]*Student, 0, 200),
}
for i := 0; i < 10; i++ {
stu := &Student{
Name: fmt.Sprintf("stu%02d", i),
Gender: "男",
ID: i,
}
c.Students = append(c.Students, stu)
}
//JSON序列化:结构体-->JSON格式的字符串
data, err := json.Marshal(c)
if err != nil {
fmt.Println("json marshal failed")
return
}
fmt.Printf("json:%s\n", data)
//JSON反序列化:JSON格式的字符串-->结构体
str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`
c1 := &Class{}
err = json.Unmarshal([]byte(str), c1)
if err != nil {
fmt.Println("json unmarshal failed!")
return
}
fmt.Printf("%#v\n", c1)
}
Structure tag (Tag)
Tag
Meta information structure can be read out by a mechanism at run-time reflection. Tag
After the structure defined above the field, by a pair of anti-wrap quotes, particularly the following format:
`key1:"value1" key2:"value2"`
Structure label of one or more key-value pairs. Keys and values separated by a colon, the value of double quotes. Use a space delimited between the pairs. Notes: written for the structure Tag
, we must strictly abide by the rules of key-value pairs. Fault tolerance for resolving a code label structure is poor, once the wrong format, will not prompt any error during compilation and run-time, by reflecting the values can not be correct. For example, do not add a space between the key and value.
For example, we Student
use the definition of each field in the structure json serialization Tag:
//Student 学生
type Student struct {
ID int `json:"id"` //通过指定tag实现json序列化该字段时的key
Gender string //json序列化是默认使用字段名作为key
name string //私有不能被json包访问
}
func main() {
s1 := Student{
ID: 1,
Gender: "男",
name: "沙河娜扎",
}
data, err := json.Marshal(s1)
if err != nil {
fmt.Println("json marshal failed!")
return
}
fmt.Printf("json str:%s\n", data) //json str:{"id":1,"Gender":"男"}
}
Exercises
- Use the "object-oriented" way of thinking to prepare a student information management systems.
- Students with id, name, age, scores and other information
- Program provides students show list, add students, student information edit, delete, students and other functions