15

golang 结构体struct

 4 years ago
source link: https://studygolang.com/articles/26152
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

struct(结构体)也是一种聚合的数据类型,struct可以包含多个任意类型的值,这些值被称为struct的字段。

1.声明一个结构体

type Person struct {
    Name string
    Age int
    Birthday time.Time
}
复制代码

结构体字段的首字母标识字段的权限访问,大写的包外可访问,小写的属于包内私有变量,仅在该结构体内部使用

2. 初始化

ts := "2000-01-01 12:00:32"
    timeLayout := "2006-01-02 15:04:05"                             //转化所需模板
    loc, _ := time.LoadLocation("Local")                            //重要:获取时区
    theTime, _ := time.ParseInLocation(timeLayout, ts, loc) //使用模板在对应时区转化为time.time类型
    fmt.Println(theTime)
    p := Person{Name:"zhanglinpeng",Age: 18, Birthday: theTime,} //最后的,不能少
    p2 := new(Persion) //new()函数来创建一个「零值」结构体,所有的字段都被初始化为相应类型的零值。返回的是结构体指针
    zerostruct := struct{}{} //空结构体,字节长度为0
复制代码

3.匿名结构体

var apr = struct {
        Name string
        Age  int
    }{
        Name: "zhanglinpeng",
        Age: 13,
    }
    fmt.Println(apr)
复制代码

4.匿名字段

var Student struct {
    string
    int
}
a := Student{"zhaoll", 19}
复制代码

注意初始化时的顺序不能变

5.嵌套

type Person struct {
    Name string
    Age     int
    Contact  struct {
        Phone, Email, QQ string
    }
}
复制代码

内嵌匿名结构体的初始化只能通过以下方式实现:

var apr = struct {
        Name string
        Age  int
        Contact struct {
            Phone, Email string
        }
    }{
        Name: "zhanglinpeng",
        Age: 13,
    }
    apr.Contact.Phone = "110"
    apr.Contact.Email = "[email protected]"
    fmt.Println(apr)
复制代码

6.值传递

结构体作为参数传递给函数时,也是值传递,如果想修改原始结构体,可以使用指针

func changeName(pr *Person) {
    pr.name = "zhanglinpeng"
}
...
changeName(&person)
fmt.Println(person)
复制代码

7.属性值获取

可以使用点操作符获取属性值,点操作符还可以应用在struct指针上。

person := &person{Name:"weishihao",Age:14,...}
person.Name = "zhaoyuhao"
复制代码

8.结构体比较

var Person struct {
    Name string
    Age int
} 
p1 := Person{Name:"zhaojj", Age: 14}
p2 := Person{Name:"zhaojj", Age: 14}
p3 := Person{Name:"zhaojj", Age: 15}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
复制代码

9.嵌入(“继承”)

type Person struct {
    Gender int
}

type teacher struct {
    Person
    Name string
    Age int
}

type student struct {
    Person
    Name string
    Age int
}

t1 := teacher{Name:"mayun", Age: 44, Person: Person{Gender: 0}}
s1 := student{Name: "zhaojj", Age: 12, Person: Person{Gender: 1}}
t1.Name = "yangmi"
s1.Gender = 0
复制代码

我们发现,修改“继承”来的属性,可以直接点操作,而不用s1.Person.Gender = 0, 虽然这样做也是可行的。 如果在嵌入的结构体中存在同名的属性字段,那么在访问不同结构体中的属性字段时,需要指明,比如上述的那种访问方式。 如果同级别的嵌入结构体存在同名属性字段,就会报错。

10.方法

我们只需要在普通函数前面加个接受者(receiver,写在函数名前面的括号里面),这样编译器就知道这个函数(方法)属于哪个struct了。 需要注意的是,因为Go不支持函数重载,所以某个接收者(receiver)的某个方法只能对应一个函数,比如下面的就属于方法重复。

type A struct {
    Name string
}
type B struct {
    Name string
}

func (a A) print() {
    fmt.Println("function A")
}

func (b B) print() {
    fmt.Println("function B")
}

func (b B) print(i int) {
    fmt.Println("function B with argument")
}
复制代码

针对A, B不同结构体print是不同的方法,所以可以和平相处,但是针对B结构体,存在两个同名的print方法,那么就会报错。

11.结构体指针

package main

import (
	"fmt"
)

type User struct {
	Id   int
	Name string
}

func (u User) displayId() {
	fmt.Println(u.Id)
}

func (u *User) displayName() {
	fmt.Println(u.Name)
}

func main() {
	us := User{Id: 1, Name: "zhao"}
	us.displayId() // 1
	us.displayName() // zhao
	us2 := &User{Id: 2, Name: "qian"}
	us2.displayId() // 2
	us2.displayName() // qian
}
复制代码

可以看出,无论是结构体变量还是结构体指针变量,都是可以调用接受者不管是结构体还是结构体指针的方法。但是,传递给接口的时候会有所不同

package main

import (
	"fmt"
)

type DisplayInfo interface {
    displayId()
    displayName()
}

type User struct {
	Id   int
	Name string
}

func (u User) displayId() {
	fmt.Println(u.Id)
}

func (u *User) displayName() {
	fmt.Println(u.Name)
}


func DisplayUserInfo(ds DisplayInfo) {
    ds.displayId()
    ds.displayName()
}

func main() {
	us := User{Id: 1, Name: "zhao"}
	us.displayId()
	us.displayName()
	us2 := &User{Id: 2, Name: "qian"}
	us2.displayId()
	us2.displayName()

	us3 :=User{Id:3,Name:"sun"} // 如果这里使用&User{Id:3,Name:"sun"}是可以运行的
	DisplayUserInfo(us3) // cannot use us3 (type User) as type DisplayInfo in argument to DisplayUserInfo
	// User does not implement DisplayInfo (displayName method has pointer receiver)

}
复制代码

错误信息中说,User类型没有实现DisplayInfo接口原因是displayName方法接受者是指针。但是为什么 us3=&User{Id:3,Name:"sun"} 可以呢?这是因为 接受者是指针类型的时候,说明指针指向的结构体实现了接口 接受者是值类型的时候,说明的是结构体本身实现了接口 .接受者是T的属于一个方法集,接受者是*T的是另一个方法集,该方法及包含接受者是*T和T的。

12.接受者的类型决定了能否修改绑定的结构体

package main

import "fmt"

type A struct {
    Name string
}
type B struct {
    Name string
}

func (a A) print() {
    a.Name = "FuncA"
    fmt.Println("function A")
}

func (b *B) print() {
    b.Name = "FuncB"
    fmt.Println("function B")
}
func main() {
    a := A{}
    a.print()
    fmt.Println(a.Name)  // ""
    b := B{}
    b.print()
    fmt.Println(b.Name) // "FuncB"
}
复制代码

13.方法绑定本身只能绑定包内的类型

如果是包外的类型,我们是无法绑定方法的。这就是为什么类型别名,无法将类型上的方法带到当前的包中的原因,比如,我在当前包中定义了一个int 类型,那么int类型上的方法,只有我们自己去实现

14. method value VS method expression

其实有两种调用方式,上面讲的那种官方管它叫method value,还有另一种调用方式,叫method expression

package main

import "fmt"

type A struct {
    Name string
}

func (a *A) print() {
    a.Name = "FuncA"
    fmt.Println("function A")
}

func main() {
    a := A{}
    a.print() // method value
    (*A).print(&a)  // method expression
    (&a).print()
}
复制代码

15.方法权限

最后说下访问权限,因为Go是以大小写来区分是公有还是私有, 但都是针对包级别的 , 所以在包内所有的都能访问,而方法绑定本身只能绑定包内的类型,所以方法可以访问接收者所有成员。

16.demo

package main

import (
    "fmt"
    "unsafe"
)

type User struct {
    subject [10]byte
}

func main() {
    user := new(User)
    fmt.Println(user.subject) // [0 0 0 0 0 0 0 0 0 0]
    fmt.Println(len(user.subject)) // 10
    fmt.Println(reflect.TypeOf(user)) // *main.User
    fmt.Println(unsafe.Sizeof(struct{}{})) // 0
}
复制代码

Recommend

  • 66
    • studygolang.com 5 years ago
    • Cache

    玩转Golang之Struct结构体

    先介绍一下go语言的类型系统 Golang中的类型系统 类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含如下基本内容:  基础类型,如byte、int、bool、float等;  复合类型,如数...

  • 16
    • studygolang.com 3 years ago
    • Cache

    Golang——结构体struct

    Go语言中没有“类”的改变,不支持类的“继承”等面向对象概念。Go语言中通过结构体的内嵌再配合接口比面向对象更具有更高的扩展性和灵活性。 自定义类型和类型别名 自定义类型:新类型,可以基于内置的基本类型定义,也...

  • 4

    大纲

  • 5

    在 Go 语言中,一个 struct 实现了某个接口里的所有方法,就叫做这个 struct 实现了该接口。 下面写一个 Demo 实现一下,先写一个 Study interface{},里面需要实现 4 个方法 Listen、Speak、Read、Write,然后再写一个 study struct{},...

  • 4

    Golang json字符串与结构互转(json to struct   struct to json)朋也的博客 » 首页 » 文章 Golang json字符串与结构互转(json to struct || struct to json) 作者:朋也日期:2021-02-24

  • 3
    • geektutu.com 2 years ago
    • Cache

    Go 空结构体 struct{} 的使用

    Go 空结构体 struct{} 的使用 源代码/数据集已上传到 Github - high-performance-go

  • 3

    The Rust programming language 读书笔记——结构体(Struct) 发表于 2021-06-09...

  • 3

    GO 语言接口与结构体 - interface & struct 坚果jimbowhy · 2019-08-02 22:32:40 · 4826 次点击 · 预计阅读时间 3 分钟 · 大约8小时之前 开始浏览    ...

  • 17
    • learnblockchain.cn 2 years ago
    • Cache

    solidity中的struct结构体问题

    solidity中的struct结构体问题 | 登链社区 | 技术问答 solidity中的struct结构体问题 ...

  • 5
    • wnanbei.github.io 2 years ago
    • Cache

    Go 结构体 struct

    Go 通过类型别名 alias types 和结构体的形式支持用户自定义类型。 定义和声明 type identifier struct { field1 type1 field2 type2 } type T struct {a, b int} 结构体的字段...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK