TOC

Golang 结构体

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
}

type User struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

type Person struct {
    Name    string  `json:"name"`
    Age     int     `json:"age"`
    Address Address `json:"address"`
    // 这么写,JSON 会多一层
    // User    `json:"user"`
    User
}

func (p Person) SayHello() {
    fmt.Println("Hello, my name is", p.Name)
}

func main() {
    person := Person{
        Name: "Bob",
        Age:  30,
        Address: Address{
            City:    "London",
            Country: "UK",
        },
        User: User{
            Username: "bob1999",
            Password: "pa55w0rd",
        },
    }

    // 属性操作
    fmt.Println("Name:", person.Name)
    fmt.Println("Age:", person.Age)
    fmt.Println("City:", person.Address.City)
    fmt.Println("Country:", person.Address.Country)
    fmt.Println("Username:", person.Username)
    fmt.Println("Password:", person.Password)
    fmt.Printf("%+v\n", person)
    fmt.Printf("%#v\n", person)

    // 方法调用
    person.SayHello()

    // 通过反射获取标签内容
    t := reflect.TypeOf(person)
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        tag := field.Tag.Get("json")
        fmt.Println(field.Name, ":", tag)
    }

    // JSON 序列化
    jsonData, err := json.Marshal(person)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println("JSON:", string(jsonData))
}

// Name: Bob
// Age: 30
// City: London
// Country: UK
// Username: bob1999
// Password: pa55w0rd
// main.Person{name:"Bob", age:30, address:main.Address{city:"London", country:"UK"}, User:main.User{username:"bob1999", password:"pa55w0rd"}}

其他知识点:

  1. 字段名大小写问题:首字母小写的话,只有本包可以访问

  2. Zero-value Struct

type Fruit struct {
    name string
}
var apple Fruit
fmt.Println(apple) // {}
  1. new 关键字
package main

import "fmt"

type Employee struct {
    Name string
    Age  int
}

func main() {
    p := new(Employee)
    fmt.Println(p) // &{ 0}

    var p2 Employee
    fmt.Println(p2) // { 0}

    p3 := Employee{"Me", 30}
    fmt.Println(p3) // {Me 30}
}
  1. struct 字面量
type Person struct {
    Name  string
    Age   int
    Email string
}

p1 := Person{
    Name:  "Alice",
    Age:   25,
    Email: "alice@example.com",
}
p2 := Person {"Alice", 25, "alice@example.com"}
  1. 指针

  2. 匿名结构体

package main

import (
    "fmt"
)

func main() {
    user := struct {
        username string
    }{
        username: "admin",
    }
    fmt.Printf("%+v\n", user)
    // {username:admin}
    fmt.Printf("%#v\n", user)
    // struct { username string }{username:"admin"}
    fmt.Printf("%v\n", user)
    // {admin}
    fmt.Println(user)
    // {admin}
}

场景:

  1. 定义一个临时结构体接收反序列化数据
  2. 内嵌结构体

  3. 匿名属性(或者应该叫啥,我也不知道)

  4. 内嵌类型不能重复,

  5. 前面的例子可以看出,可以直接访问匿名属性(结构体)内部属性,
  6. 但是如果同名就只能老老实实通过类型名字来访问了
package main

import (
    "fmt"
)

type Book struct {
    string // book name (anno field)

    // syntax error: unexpected [, expected field name or embedded type
    // []Author
    Authors []Author // slice of authors

    Publisher
}

type Author struct {
    string // author name (anno field)
}

type Publisher struct {
    string // publisher name (anno field)
}

func main() {
    p := Book{
        string: "Learning Python",
        Authors: []Author{
            {string: "Stanley B.Lippman"},
            {string: "Josée LaJoie"},
            {"Barbara E.Moo"},
        },
        Publisher: Publisher{"人民邮电出版社"},
    }
    p.string = "C++ Primer" // change attr

    fmt.Println(p)
    fmt.Printf("%v\n", p)
    fmt.Printf("%+v\n", p)
    fmt.Printf("%#v\n", p)
    fmt.Printf("%v\n", p.string)
    fmt.Printf("%v\n", p.Authors[0].string)
    fmt.Printf("%v\n", p.Publisher)
    fmt.Printf("%v\n", p.Publisher.string)
}

// {C++ Primer [{Stanley B.Lippman} {Josée LaJoie} {Barbara E.Moo}] {人民邮电出版社}}
// {C++ Primer [{Stanley B.Lippman} {Josée LaJoie} {Barbara E.Moo}] {人民邮电出版社}}
// {string:C++ Primer Authors:[{string:Stanley B.Lippman} {string:Josée LaJoie} {string:Barbara E.Moo}] Publisher:{string:人民邮电出版社}}
// main.Book{string:"C++ Primer", Authors:[]main.Author{main.Author{string:"Stanley B.Lippman"}, main.Author{string:"Josée LaJoie"}, main.Author{string:"Barbara E.Moo"}}, Publisher:main.Publisher{string:"人民邮电出版社"}}
// C++ Primer
// Stanley B.Lippman
// {人民邮电出版社}
// 人民邮电出版社
  1. 将函数通过属性的方式定义
type FoodNameGetter func(string) string

type Food struct {
    name   string
    getter FoodNameGetter // declare function
}

pizza := Food{
    name: "Pizza",
    getter: func(name string) string { // declare function body
        return "This is " + name + "."
    },
}
  1. 结构体比较

如果类型和值相同,就等于。

package main

import "fmt"

type Teacher struct {
    name string
}

type Student struct {
    name string
}

func main() {
    s1 := Student{"John"}
    s2 := Student{"John"}
    fmt.Println(s1 == s2) // true

    // invalid operation: s1 == t1 (mismatched types Student and Teacher)
    // t1 := Teacher{"John"}
    // fmt.Println(s1 == t1)
}

参考资料与拓展阅读