Go基础学习-struct、method

结构体

  • 可以封装多个基本数据类型;来实现面向对象;是值类型;占用一块连续的内存空间
  • 相同struct类型的可以比较;不同struct类型的不可以比较;结构体是否相同不但与属性类型个数有关,还与属性顺序相关;但是结构体属性中有不可以比较的类型,如map,slice。
    func main(){
    	type A struct {
    			a int
    		}
    	type B struct {
    		a int
    	}s
    	a := A{1}
    	b := A{2}  
    	//b := B{1}   //编译错误
    	if a == b {
    		fmt.Println("a == b")
    	}else{
    		fmt.Println("a != b")
    	}
    }
    //output:a!=b
    
     sn1 := struct {
        age  int
        name string
    }{age: 11,name: "qq"}
    
    sn3:= struct {
        name string
        age  int
    }{age:11,name:"qq"}
    //sn3与sn1就不是相同的结构体了,不能比较。
    
    sm1 := struct {
    	age int
    	m   map[string]string
    }{age: 11, m:map[string]string{"a": "1"}}
    sm2 := struct {
    	age int
    	m   map[string]string
    }{age: 11, m:map[string]string{"a": "1"}}
    //sm1、sm2不可以比较;结构体属性中有不可以比较的类型,如map,slice。
    //但是可以通过reflect.DeepEqual()来进行比较;
    if sm1 == sm2 {  //错的
    	fmt.Println("sm1== sm2")
    }
    //可以通过reflect.DeepEqual()来实现比较
    if reflect.DeepEqual(sm1, sm2) {
    	fmt.Println("sm1==sm2")
    }else {
    	fmt.Println("sm1!=sm2")
    }
    

关于Go语言中的内存对齐 :推荐阅读:在 Go 中恰到好处的内存对齐

/*
定义:
type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …
}
类型名:标识自定义结构体的名称,在同一个包内不能重复。首字母大写对外包引用
字段名:表示结构体字段名。结构体中的字段名必须唯一。对外包引用首字符必须大写
字段类型:表示结构体字段的具体类型。
*/
type person struct {
	name   string
	gender string
	age    int
	hobby  []string
}
type person struct {
	name,gender    string
	age    int
	hobby  []string
}
//匿名字段:结构体允许其成员字段在声明时没有字段名而只有类型;默认会采用类型名作为字段名
type Person struct {
	string
	int
}
//初始化,没有初始化的返回对应类型的零值
//方法1
var person1 person
person1.name = "zhangsan"
person1.age = 3000
person1.gender = "男"
person1.hobby = []string{
	"更好",
	"优秀",
	"up",
}
fmt.Println(person1)

//方法2;使用值列表的形式初始化  但是字段顺序必须要和声明的结构体字段顺序一致  且字段不能少必须全部写上
p3 := person{
	"tiedan",
	1000,
	"男",
	[]string{
		"up", "fight",
	},
}

//匿名结构体 (多用于临时场景)
var s struct {
	name string
	age  int
}
s.name = "zhangsan"
s.age = 1000
fmt.Printf("%T %v\n", s, s)
//结构体指针1
var p1 = new(person) //new返回的是指针 相当于p1 := &person{}
p1.name = "gaiya" //语法糖果  相当于 (*p1).name="gaiya"
fmt.Printf("%T %p\n", p1, p1)
//结构体指针2
//key-value 初始化
var p2 = person{
	name: "tiezhu",
	age:  2000,
}
fmt.Printf("%#v\n", p2)
//结构体嵌套
type addres struct {
	province string
	city     string
}

type person struct {
	name string
	age  int
	addr addres
}
type company struct {
	name   string
	addres //匿名结构体嵌套
}

func main() {
	p1 := person{
		name: "tiezhu",
		age:  2000,
		addr: addres{
			province: "安徽",
			city:     "合肥",
		},
	}
	c1 := company{
		name: "公司",
		addres: addres{
			province: "浙江",
			city:     "杭州",
		},
	}
	fmt.Println(p1, p1.addr.city)
	fmt.Println(c1, c1.city) //只适用于匿名结构体的嵌套  会首先从自己的结构体中找字段 没有的话就去匿名结构体中寻找

}
//用结构体模拟实现其他语言中的“继承”
type fath struct {
	name string
}

//给fath 实现一个move方法
func (a fath ) F() {
	fmt.Printf("%s。。。\n", a.name)
}

type ch struct {
	feet   uint8
	fath  //fath 拥有的方法,ch 也会拥有
}

//给ch 实现一个C方法
func (d ch) C() {
	fmt.Printf("%s。。。”\n", d.name)
}

func main() {
	d1 := ch{
		feet: 4,
		fath: fath{
			name: "gaiya",
		},
	}
	fmt.Println(d1)
	d1.F()
	d1.C ()
}
//结构体标签(Tag)
type Student struct {
	ID     int    `json:"id" form:"id"` //通过指定tag实现json序列化该字段时的key
	Gender string //json序列化是默认使用字段名作为key
	name   string //私有不能被json包访问
	Age int `json:"age,omitempty"`//omitempty 忽略空值 ,0、”” 等在传递的时候会被忽略
	Hoby string `json:"_"`//"_"完全跳过字段
}
  • 结构体由一个或多个键值对组成,键与值使用冒号分隔,值用双引号括起来;不同的键值对之间使用空格分隔
  • 结构体标签的解析代码的容错能力很差;一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值;例如不要在key和value之间添加空格
//匿名空结构体
var a struct{}
var a =struct{}{}//实例化的话也不占内存;所以匿名空的结构体一般用来做通知使用:
//结构体和json转换
//1.序列化:Go语言中结构体变量转换为json格式的字符串
//2.反序列化:json格式的字符串转换为Go语言中可以识别的结构体变量

type person struct {
	Name string `json:"name"` //因为结构体会传入到Marshal函数中所以字段必须是大写的才可以被别的包调用
	Age  int    `json:"age"`  //``是为了指定转换为对应格式的字段名。json:"age"标识转json时该字段显示为age
}

func main() {
	p1 := person{
		Name: "Bradley",
		Age:  18,
	}
	fmt.Printf("%v\n", p1)
	//序列化
	v, error := json.Marshal(p1)
	if error != nil {
		fmt.Printf("error is %v\n", error)
		return
	}
	fmt.Printf("%v\n", string(v))
	//反序列化
	str := `{"name":"coope","age":20}`
	var p2 person
	json.Unmarshal([]byte(str), &p2) //因为是传入函数且是修改  所以需要传入的是指针
	fmt.Printf("%#v\n", p2)
}

因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以在传递结构体时使用指针类型

method

方法:method;

  • 是作用于特定类型的函数;接收者表示的是调用该方法的具体类型变量,多用类型名的首字母来作为变量;
  • 接收者的概念就类似于其他语言中的this或者 self。
  • 接收者必须是自己包里定义的类型,不能是内置的类型如int 如果需要可以自定义int:(type myint int)
  • 接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法
  • 非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法
//指针类型接收者
func (d *dog) wang() { //因为go函数传的值永远是拷贝的值,所以当需要修改接收者中的值的时候,需要传指针
	d.age++ //语法糖果:相当于(*d).age++
	fmt.Printf("%s ww...\n", d.name)
}
//值接收者
func (d dog) wang2() {
	fmt.Printf("%s ww...\n", d.name)
}

//MyInt 将int定义为自定义MyInt类型
type MyInt int
func (m MyInt) SayHello() {
	return
}
//由于slice、map这两种数据类型是引用类型,都包含了指向底层数据的指针,因此我们在需要复制它们时要特别注意;需要传他们的copy进行赋值
type Person struct {
	name   string
	age    int8
	dreams []string
}
func (p *Person) SetDreams(dreams []string) {
	p.dreams = dreams
}
func main() {
	p1 := Person{name: "zs", age: 18}
	data := []string{"a", "b", "c"}
	p1.SetDreams(data)
	
	data[1] = "B"
	fmt.Println(p1.dreams)  // ouput:{"a", "B", "c"}
}
//正确做法是 
func (p *Person) SetDreams(dreams []string) {
	p.dreams = make([]string,len(dreams))
	p.dreams=dreams 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值