Go语言学习5:结构体、方法

struct结构体

结构体是用户定义的类型,表示若干个字段的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。Go 语言中没有类的概念,结构体就像是类的一种简化形式。

命名的结构体

package main

import (
    "fmt"
)

type Employee struct {
    firstName, lastName string
    age, salary         int
}

func main() {

    //creating structure using field names
    emp1 := Employee{
        firstName: "Sam",
        age:       25,
        salary:    500,
        lastName:  "Anderson",
    }

    //creating structure without using field names
    emp2 := Employee{"Thomas", "Paul", 29, 800}

    fmt.Println("Employee 1", emp1)
    fmt.Println("Employee 2", emp2)
    fmt.Println("emp2 age:", emp2.age)

    emp2.age = 30
    fmt.Println("emp2 new age:", emp2.age)
}

当定义好的结构体并没有被显式地初始化时,该结构体的字段将默认赋为其类型的零值。

匿名的结构体

package main

import (
    "fmt"
)

func main() {
    emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

    fmt.Println("Employee 3", emp3)
}

结构体指针

package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", emp8.age)
}

Go 语言允许我们在访问结构体字段时省略*符号。

匿名字段

package main

import (
    "fmt"
)

type Person struct {
    string
    int
}

func main() {
    p := Person{"Naveen", 50}
    fmt.Println(p)
    fmt.Println(p.int)
}

字段可以只有类型,而没有字段名。这样的字段称为匿名字段。虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。

提升字段

如果结构体A中嵌套了一个结构体B,则可以通过A.B.x来访问B中的变量x。但如果是结构体中嵌套的是匿名的结构体类型字段呢?此时该匿名结构体里的字段就称为提升字段,可以用外部结构体直接访问。举例:

package main

import (
    "fmt"
)

type Address struct {
    city, state string
}
type Person struct {
    name string
    age  int
    Address
}

func main() {
    var p Person
    p.name = "Naveen"
    p.age = 50
    p.Address = Address{
        city:  "Chicago",
        state: "Illinois",
    }
    fmt.Println("Name:", p.name)
    fmt.Println("City:", p.city) //city is promoted field
}

如果外部结构体和内部嵌套结构体都包含有相同的字段名,访问时外部结构体优先。

方法

Go 方法是作用在接收者上的一个函数,接收者是某种类型的变量。因此方法是一种特殊类型的函数。

package main

import (
    "fmt"
)

type Employee struct {
    name     string
    salary   int
    currency string
}

/*
  displaySalary() 方法将 Employee 做为接收器类型
*/
func (e Employee) displaySalary() {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}

func main() {
    emp1 := Employee {
        name:     "Sam Adolf",
        salary:   5000,
        currency: "$",
    }
    emp1.displaySalary() // 调用 Employee 类型的 displaySalary() 方法
}

如果作用在外部结构体和内部嵌套结构体上的方法有相同的方法名,访问时外部结构体优先,这就和重写一个道理,可以视外部结构体为子类。

为什么我们需要方法?使用函数不可以吗?

  • Go 不是纯粹的面向对象编程语言,而且Go不支持类。因此,基于类型的方法是一种实现和类相似行为的途径。
  • 相同的名字的方法可以定义在不同的类型上,而相同名字的函数是不被允许的。

指针接收器

package main

import (
    "fmt"
)

type Employee struct {
    name string
    age  int
}

//使用值接收器的方法。
func (e Employee) changeName(newName string) {
    e.name = newName
}

//使用指针接收器的方法。
func (e *Employee) changeAge(newAge int) {
    e.age = newAge
}

func main() {
    e := Employee{
        name: "Mark Andrew",
        age:  50,
    }
    fmt.Printf("Employee name before change: %s", e.name)
    e.changeName("Michael Andrew")
    fmt.Printf("\nEmployee name after change: %s", e.name)

    fmt.Printf("\n\nEmployee age before change: %d", e.age)
    e.changeAge(51)
    fmt.Printf("\nEmployee age after change: %d", e.age)
}

指针接收器适用范围:

  • 方法能够修改其接收者指向的值。
  • 当拷贝一个结构体的代价过于昂贵时。

学习资料:https://studygolang.com/subject/2

你可能感兴趣的:(Go)