结构体
go语言中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的数据类型明显就无法满足需求了,go原因提供了一种自定义的数据类型,.可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct.也就是我们通过struct来定义自己的类型了
go语言中通过struct来面向对象
结构体基本
package main
import "fmt"
type person struct {
name string
age int
gender string
hobby []string
}
func main() {
var p person
p.name = "zhoulin"
p.age = 9000
p.gender = "男"
p.hobby = []string{"篮球", "足球", "双色球"}
fmt.Println(p) //{zhoulin 9000 男 [篮球 足球 双色球]}
//访问变量p的字段
fmt.Println(p.name) //zhoulin
fmt.Printf("%T\n", p) //main.person
//匿名结构体,多用于临时场景
var s struct {
x string
y int
}
s.x = "嘿嘿"
s.y = 100
fmt.Println(s) //{嘿嘿 100}
fmt.Printf("%T\n", s) //struct { x string; y int }
}
结构体指针,和结构体初始化
package main
import "fmt"
type person struct {
name string
gender string
}
func f(x person) {
x.gender = "女"
}
func f2(x *person) {
(*x).gender = "女" //根据内存地址找到原变量,修改的就是原来的变量
x.gender = "女" //go无法修改指针,这种写法和上面的写法作用一样(语法糖)
}
func main() {
var p person
p.name = "周林"
p.gender = "男"
f(p)
fmt.Println(p.gender) //打印结果还是为男,因为内部修改的是局部的变量
f2(&p) //
fmt.Println(p.gender) //女
//结构体指针1
var p2 = new(person)
p2.name = "理想" //语法糖相当于 (*p2).name="理想"
fmt.Printf("%T\n", p2) //*main.person
//2结构体指针2
//使用key-value初始化
var p3 = person{
name: "元帅",
gender: "男",
}
fmt.Printf("%#v\n", p3) //main.person{name:"元帅", gender:"男"}
//使用列表形式初始化
//值的顺序要和结构体定义时字段的顺序一致
p4 := person{
"王子",
"男",
}
fmt.Printf("%#v\n", p4) //main.person{name:"王子", gender:"男"}
}
结构体和接收者
package main
import "fmt"
type dog struct {
name string
}
//
func newDog(name string) dog {
return dog{
name: name,
}
}
//方法是作用于特定类型的函数
//函数前面的是接收者
//接收者表示的是调用改类型方法的具体变量,多用类型名首字母表示
func (d dog) wang() {
fmt.Printf("%s:汪汪汪\n", d.name)
}
func main() {
d1 := newDog("zhoulinn")
d1.wang()
}
方法接收者
go语言中的方法是一种工作用于特定类型变量的函数.这种特定类型变量叫做接收者.接收者的概念就类似于其他语言中的this或者self
方法的定义格式如下:
func (接收者变量 接收者类型)方法名(参数列表)(返回参数){
函数体
}
接收者类型:接收者类型和参数类似,可以是指类型和非指针类型
方法名,参数列表,返回参数:具体格式与函数定义相同
标识符
go语言中如果标识符首字母是大写的,就表示对外部包可见(暴露的,共有的)
值接收者和指针接收者的区别
package main
import "fmt"
type dog struct {
name string
}
type person struct {
age int
name string
gender string
}
//
func newDog(name string) dog {
return dog{
name: name,
}
}
func (p person) guonian() {
p.age++
}
func (p *person) zhenguonian() {
p.age++
}
//方法是作用于特定类型的函数
//函数前面的是接收者
//接收者表示的是调用改类型方法的具体变量,多用类型名首字母表示
func (d dog) wang() {
fmt.Printf("%s:汪汪汪\n", d.name)
}
func main() {
d1 := newDog("zhoulinn")
d1.wang()
var p1 person
p1.guonian()
fmt.Println(p1.age) //还是0没有改变
p1.zhenguonian() //相当于把内存地址传入了
fmt.Println(p1.age) //值为1 成功的改变了
}
什么时候应该使用指针类型接收者
- 需要修改接收者的值
- 接收者是拷贝代价比较大的打对象
- 保证一致性,如果有某个方法
任意类型方法
在go语言中接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法.
package main
import "fmt"
type myInt int
func (i myInt) hello() {
fmt.Println("我是一个int")
}
func main() {
var m myInt
m = 10 //不能写成m:=10
m.hello() //我是一个int
}
结构体的传递
go语言中对象的赋值是直接将整个对象进行赋值的,而不是像其他语言一样赋值对象的内存地址
package main
import "fmt"
type obj struct {
one string
two int
}
func main() {
var o obj
o.one = "name"
c := o
o.one = "name2"
fmt.Println(o, c) //{name2 0} {name 0}
}
匿名字段
相同类型只能出现一次
package main
import "fmt"
type person struct {
string
int
}
func main() {
p1 := person{
"666",
666,
}
fmt.Println(p1.string, p1.int) //666 666
}
嵌套结构体
package main
import "fmt"
type person struct {
name string
age int
}
type company struct {
size int
ren person
}
func main() {
p1 := person{
name: "周琳",
age: 9000,
}
c1 := company{
size: 2,
ren: person{ //也可以直接写p1
name: "name1",
age: 5,
},
}
fmt.Println(p1)
fmt.Println(c1)
}
继承与匿名结构体
go语言使用结构体也可以实现其他语言的继承
package main
import "fmt"
type animal struct {
name string
}
//给animal实现一个移动的方法
func (a animal) move() {
fmt.Printf("%s会动\n", a.name)
}
//狗
type dog struct {
feet uint8
animal //这样就实现了继承
}
func (d dog) wang() {
fmt.Println("旺旺", d.name) //如果没有找到d.name这个属性会去dog中的animal中找
}
func main() {
d1 := dog{
animal: animal{name: "zzz"},
feet: 4,
}
d1.animal.move() //也可以这样用
d1.move() //效果一样
fmt.Println(d1) //{4 {zzz}}
}
结构体与json
1序列化 把go语言中的结构体变量->json格式的字符串
2反序列化 json格式的字符串->gio语言中能够识别的结构体变量
package main
import (
"encoding/json"
"fmt"
)
type person struct {
Name string //格式化的功能使用json包中的Marshal方法做的,所以需要被拿到必须大写
Age int `json:"age"` //如果用json解析的时候就设置成小写
}
func main() {
p1 := person{
Name: "zl",
Age: 9000,
}
b, err := json.Marshal(p1) //序列化
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
//饭序列化
str := `{"Name":"zl","Age":9000}`
var p2 person
json.Unmarshal([]byte(str), &p2) //需要让函数修改必须传入指针,是为了让函数内部去修改p2的值
fmt.Println(p2) //{zl 9000}
}