Go (三) 面向对象1
最佳答案 问答题库848位专家为你答疑解惑
一、面向对象
1.1、初识golang面向对象
golang支持面向对象编程(OOP)。
golang没有类(class),go语言的结构体(struct)和其他编程语言的类(class)有同等的地位。简单理解golang是根据struct来实现面向对象编程(OOP)的。
golang有面向对象的继承,封装和多态的特性
golang面向对象很优雅,通过(interface)关联,耦合性低,很灵活。也就是说golang中面向接口编程是非常重要的特性。
二、结构体(struct)和结构体变量(值类型)
2.1、结构体(struct)和结构体变量的快速入门(更多方式:详见2.4)
// 定义结构体变量,也叫做"对象" type Cat struct {Name stringAge intColor string }func main() {// 创建一个结构体变量"cat",类型为"Cat",是一个structvar cat1 Catfmt.Println(cat1) // 返回的默认值:{ 0 } ,string默认值为"",int默认值为0,所以这里显示只有一个0// 给变量的"属性"赋值cat1.Color="yellow"cat1.Age=2cat1.Name="dandan"fmt.Println(cat1) // 返回值:{dandan 2 yellow} 分别对应Name,Age,Color的值fmt.Println(cat1.Name) // 返回值:dandanfmt.Println(cat1.Age) // 返回值:2fmt.Println(cat1.Color) // 返回值:yellowfmt.Printf("%T",cat1) // 类型:main.Cat }
2.2、结构体变量在内存中的布局(重要)
1.声明一个结构体变量时,数据结构已经存在了,数据的值就是不同类型的默认值;
2.结构体变量是值类型(相互数据不影响,如果想要相互数据影响的话,详见:2.5)
2.3、结构体(struct)声明
type 结构体名称 struct {
field1 type
field2 type
}
2.3.1、结构体(struct)声明例子
结构体名称首字母大写,那么结构体可以在其他包被使用
结构体(字段|属性)首字母大写,那么结构体字段可以在其他包被使用
不同结构体变量的字段是独立的,互不影响
type Cat struct {
Name string // (字段|属性)是string类型
Age int // (字段|属性)是int类型
Color string // (字段|属性)是string类型
}2.3.2、创建一个结构体变量后,如果没有给字段赋值,那么会有一个默认值:
布尔类型的默认值是:false
string类型的默认值是:""
int类型的默认值是:0
指针,slice(切片)和map的默认值都是nil,即没有分配内存空间(在使用时,需要先make)
例子如下:
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge intpar1 *int // 指针slice1 []int // 切片map1 map[string]string // map }func main() {// 定义结构体变量var test Testfmt.Println(test.par1) // 默认值:<nil>fmt.Println(test.slice1) // 默认值:[]fmt.Println(test.map1) // 默认值:map[]if test.par1 == nil {fmt.Println("test.par1 is nil")}if test.slice1 == nil {fmt.Println("test.slice1 is nil")}if test.map1 == nil {fmt.Println("test.map1 is nil")}// 依次输出:// test.par1 is nil// test.slice1 is nil// test.map1 is nil// 此时给"结构体变量"直接赋值,一定会报错。需要先给切片make,在使用test.slice1=make([]int,2)test.slice1[0]=111test.slice1[1]=222fmt.Println(test.slice1) // [111 222]//需要先给map make,在使用test.map1=make(map[string]string)test.map1["name"]="sudada"test.map1["age"]="18"fmt.Println(test.map1) // map[age:18 name:sudada] }
2.4、结构体变量的声明和结构体变量字段使用
2.4.1、方式1(先声明结构体变量,然后赋值)
var test struct
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {var test Testtest.Name="sudada"test.Age=18fmt.Println(test) // {sudada 18} }
2.4.2、方式1的延伸(先声明结构体变量,然后赋值)
var test = struct{}
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {var test = Test{}// 简写 test := Test{}test.Name="sudada"test.Age=18fmt.Println(test) // {sudada 18} }
2.4.3、方式2(声明结构体变量,同时赋值)
var test = struct{Name: "sudada",Age: 18,}
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {var test = Test{Name: "sudada",Age: 18,}fmt.Println(test) // {sudada 18} }
2.4.4、方式3(结构体变量是一个指针时,然后赋值)
var test *struct = new(struct)
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {// 结构体变量是一个"指针"var test *Test = new(Test) // 可以写成:var test = new(Test)// 给"指针"类型的"结构体变量"字段赋值的方式(标准写法)(*test).Name="sudada"(*test).Age=18fmt.Println(*test) // {sudada 18}// go为了程序使用方便,针对"指针"类型的结构体变量,底层做了优化:test.Age=18 == (*test).Age=18test.Name="wang"test.Age=28fmt.Println(*test) // {wang 28} }
2.4.5、方式3的延伸(结构体变量是一个指针时,然后赋值)
var test *struct = &struct{}
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {// 结构体变量是一个"指针"var test *Test = &Test{}// 给"指针"类型的"结构体变量"字段赋值的方式(标准写法)(*test).Name="sudada"(*test).Age=18fmt.Println(*test) // {sudada 18}// go为了程序使用方便,针对"指针"类型的结构体变量,底层做了优化:test.Age=18 == (*test).Age=18test.Name="wang"test.Age=28fmt.Println(*test) // {wang 28} }
2.4.6、方式4(结构体变量是一个指针,同时赋值)
var test *struct = &Test{Name:"sudada", Age:28,}
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {// 结构体变量是一个"指针",声明时赋值var test *Test = &Test{Name:"sudada",Age:28,}fmt.Println(*test) // {sudada 28}// go为了程序使用方便,针对"指针"类型的结构体变量,底层做了优化:test.Age=18 == (*test).Age=18test.Name="wang"test.Age=28fmt.Println(*test) // {wang 28} }
2.5、结构体变量的将指针赋值给另外一个结构体变量时,内存分配机制
"test2指针"对应的"值"是"test1的指针地址"(那么修改test1或者test2时,2边的值都会跟着改变)
// 定义结构体变量,也叫做"对象" type Test struct {Name stringAge int }func main() {var test1 = Test{}test1.Name="sudada"test1.Age=18// 把test1的"指针"赋值给test2fmt.Printf("%p\n",&test1) // test1的指针是:0xc000008048var test2 *Test = &test1fmt.Printf("%p\n",&test2) // test2的指针是:0xc00006a028(test2的指针存放的值就是test1的指针)fmt.Printf("%p\n",test2) // test2的值(等于test1的指针)是:0xc000008048fmt.Println(*test2) // test2:{sudada 18}// 修改"指针"的值时,test1和test2对应的值都会改变test2.Name="wang"fmt.Println(test1) // test1:{wang 18}fmt.Println(*test2) // test2:{wang 18} }
2.6、结构体struct 注意事项
2.6.1、结构体和其他类型进行转换时,需要有完全相同的字段(字段名字,字段个数和字段类型)
type A struct {Name stringAge int }type B struct {Name stringAge int }func main() {var a Avar b B// 这样强制转换不会报错(A B结构体字段名称,字段个数和字段类型相同)a = A(b)fmt.Println(a,b) // { 0} { 0} }
2.6.2、结构体进行type重新定义(相当于取别名),goloang认为是新的数据,但是相互间可以强转
// 结构体1 type Student struct {Name stringAge int } // 结构体2 type Stu Studentfunc main() {var stu1 Studentvar stu2 Stu// 这样强制转换不会报错(Student Stu结构体字段名称,字段个数和字段类型相同)stu1 = Student(stu2)fmt.Println(stu1,stu2) // { 0} { 0} }
2.6.3、结构体的每个字段都可以写一个tag,该tag可以通过反射机制获取
type student struct {
Name string `json:"name"`
Age int `json:"age"`
Sex string `json:"sex"`
}import ("encoding/json""fmt" )// 结构体1 type student struct {Name string `json:"name"`Age int `json:"age"`Sex string `json:"sex"` }func main() {var stu1 = student{"sudada",18,"nan",}fmt.Println(stu1) // {sudada 18 nan}// 把结构体变量stu1序列化(这里传入"结构体字段"必须大写,如果不大写"结构体字段",那么json.Marshal读取不到值)jsonStr, err := json.Marshal(stu1)if err != nil {fmt.Println("报错: ",err)} else {fmt.Println(string(jsonStr)) // 默认返回的是bytes类型的切片,需要使用string做一下转换// 返回值(json格式):{"Name":"sudada","Age":18,"Sex":"nan"}// 结构体字段使用tag之后:// 返回值(json格式):{"name":"sudada","age":18,"sex":"nan"}} }
三、方法
3.1、什么是方法?
glang中的方法是作用在指定的数据类型上的,即:和指定的数据类型绑定,因此自定义类型,都可以有方法。而不仅仅是struct
3.2、
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"Go (三) 面向对象1":http://eshow365.cn/6-36554-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: 什么是运营商精准大数据?又有什么作用?
- 下一篇: 【自然语言处理】基于python的问答系统实现