当前位置:首页 > 编程笔记 > 正文
已解决

Go (三) 面向对象1

来自网友在路上 184884提问 提问时间:2023-11-09 21:30:23阅读次数: 84

最佳答案 问答题库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 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!