golang指针、结构体、接口

66 阅读6分钟

指针

/*
1、类型前放*表示这个类型的指针
2、在变量前加&表示这个变量的地址
3、在指针变量前加*表示对这个指针变量进行取值
*/
// 指针的零值是nil
// 如果是数组类型指针不用解引用,直接使用下表取值// 指针数组(数组里面放一堆指针),数组指针(指向数字的指针)
// 指针数组
var x,y,z=7,8,9
var p1 [3]*int = [3]*int{&x,&y,&z}
fmt.Println(p1)
​
// 数组指针
var testatty = [3]int{1,4,6}
var p2 *[3]int = &testatty
fmt.Println(p2)

结构体

// Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。Go语言中通过struct来实现面向对象
// 定义结构体语法:结构体的零值是每一个字段的零值
type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …
}
​
type Person struct {
    name string
    age int
    hobby []string
}
​
func main()  {
    var person Person  // 定义没有初始化,结构体是值类型
    fmt.Println(person)
​
    hobby1 :=make([]string,3,4)
    hobby2 := append(hobby1, "nanqiu")
    var person1 Person=Person{"hector",19, hobby1}  // 按照位置传值,按照顺序
    var person2 Person=Person{name: "hector",age: 19, hobby: hobby2}  // 按照位置传值,不按照顺序
    fmt.Println(person2)
    fmt.Println(person1)
}
​
// 初始化后并使用结构体
person2.name = "bili"
person1.hobby[0] = "足球"
fmt.Println(person1.name)
fmt.Println(person2)
​
// 匿名结构体,创建结构体没有关键字type和结构体名字
s := struct {
    name string
    age int
}{name: "sary", age: 19}
fmt.Println(s.age)
​
// 结构体中匿名字段,类型不能重复
type Animal struct {
    int
    string
}
var anmail Animal = Animal{1,"dog"}   //按位置
var anmail1 Animal = Animal{int:1,string:"dog"}  //用类型当关键
fmt.Println(anmail1, anmail)
}
​
// 结构体嵌套,可嵌套有名结构体也可嵌套无名结构体,结构体中含有匿名结构体使用关键字创建
type Zhong struct {
    name string
}
type Dog struct {
    name string
    age int
    zhong Zhong
    qian struct{
        salary float32
    }
}
//var dog1 = Dog{"shagou", 3, Zhong{"tianyuanquan"}}
var dog2 = Dog{name:"shagou", age:3, zhong:Zhong{"tianyuanquan"}}  
dog2.qian.salary = 12.9
fmt.Println(dog1.zhong.name)
dog2.zhong.name = "dubing"
fmt.Println(dog2)
​
// 结构体嵌套加匿名字段结构体,字段提升,相当于外层结构体继承了内层结构体的部分字段
type Zhong struct {
    name string
    price float32
}
type Dog struct {
    name string
    age int
    Zhong
}
​
var dog1 = Dog{name: "xiaonaigou", age:12, Zhong:Zhong{name: "hashiqi", price: 129.01}}
fmt.Println(dog1.Zhong.name)
fmt.Println(dog1.price)
​
// 结构体相等性,结构体是值类型所以可以使用==进行比较,但具体还的看结构体中字段,如果结构体中含有不可比较字那就不能比较

方法

// 结构体是传统面向对象的一部分:即属性
// 方法其实就是函数只不过是绑定给结构体的函数,在func这个关键字和方法命中加入一个特殊的接收器类型,接收器可以是结构体类型,接收器是可以在方法的内部访问的type Personal struct {
    name string
    age int
}
​
func (person Personal)PrintName()  {
    fmt.Println(person.name)
}
​
func main()  {
    var personal = Personal{"bili", 19}
    personal.PrintName()
}
​
// 接收器和指针接收器:当拷贝一个结构体的代价过于昂贵或者修改原有值时使用指针类型接收器
type Personal struct {
    name string
    age int
}
​
func (person Personal)PrintName()  {
    fmt.Println(person.name)
}
​
func (person Personal)Editname(name string) {   // 值类型接收器修改后不会改变原来的
    person.name =name
}
​
// 指针类型接收器修改后会改变原有的,相当于python中self
func (person *Personal)EditName1(name string) {  
    person.name = name
}
​
func main()  {
    var personal = Personal{"bili", 19}
    var personal1 = Personal{"bili", 19}
    personal.PrintName()
    personal.Editname("hector")
    personal1.EditName1("hector")
    fmt.Println(personal)  // {bili 19}
    fmt.Println(personal1)  // {hector 19}
}
​
// 匿名字段的方法(结构体嵌套匿名结构体的相当于面向对象中继承,字段提升和方法提升相当于集成父类的方法)
func main() {
    animal := Animal{name: "dog", age: 2, Hobby:Hobby{hobbyid: 1, hobbyname: "wannib"}}
    fmt.Println(animal.hobbyname)
    animal.ShowAnimal()
    animal.Prihobby()
}
​
type Hobby struct {
    hobbyid int
    hobbyname string
}
​
func (hobby Hobby)Prihobby()  {
    fmt.Println("此爱好是%s", hobby.hobbyname)
}
​
type Animal struct {
    name string
    age int
    Hobby
}
​
func (anl Animal)ShowAnimal()  {
    fmt.Println("动物的名字%s",anl.name)
}
​
// 在方法中使用指针接收器,在函数中使用指针参数
func Editname2(person *Personal, name string)  {
    person.name = name
}
​
type Personal struct {
    name string
    age int
}
​
func (person *Personal)EditName1(name string) {   // 指针类型接收器修改后会改变原有的
    person.name = name
}
​
var personal1 = Personal{"bili", 19}
var peind *Personal = &personal1
personal.PrintName()
Editname2(peind, "sary")  // 执行函数
personal1.EditName1("lu")  // 执行方法
​
​
// 给非结构体绑定方法
type  Myint int8func (i *Myint)add()  {
    (*i) ++
}

结构体取代类

// go项目中取代类,在项目中创建一个文件夹entity,每个文件代表一个类,文件中是结构体以及方法,创建一个New函数来实例化结构体,每个go文件会有限执行init函数
// entity/Personal.go
package day03
​
import "fmt"type Personal struct {
    Name string
    Age int
    Hobby []string
}
​
func New(name string, age int, hobby []string) Personal {
    person := Personal{Name:name, Age:age, Hobby: hobby}
    return person
}
​
func init()  {
    fmt.Println("调用此包会自动执行init函数")
}
​
// 使用Personal类
hobby := make([]string,3 ,4)
res :=day03.New("hector", 19, hobby)
fmt.Println(res)

接口

// 在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定。接口中方法本身是一个固定的方法,该方法使用具体的效果,根据接口接受到的对象而定,即多态。
type Duck interface {
    speak(str string)   // speak方法
}
​
type Tduck struct {
    name string
    age int
}
type Pduck struct {
    name string
    age int
}
​
func (t Tduck)speak(str string)  {
    fmt.Println("这是Tduck的speak:%s", str)
}
func (p Pduck) speak(str string)  {
    fmt.Println("这是Pduck的speak:%s", str)
}
​
func main()  {
    var tduck = Tduck{name: "tdy",age: 12}
    var pduck = Tduck{name: "pdy",age: 10}
    var duck Duck
    var duck1 Duck
    duck=tduck
    duck1=pduck
    duck.speak("yayaya")
    duck1.speak("aaaaa")
}
​
// 接口的实际用途:一个函数将定义的接口类型传入,执行接口中的方法,至于接口方法所表现出的行为还得根据接口接收的对象而定
package main
​
import "fmt"type Speak interface {
    say()
}
​
type RDuck struct {
}
​
func (r RDuck)say()  {
    fmt.Println("RDuck说出的话")
}
​
type BDuck struct {
}
​
func (B BDuck)say()  {
    fmt.Println("BDuck说出的话")
}
​
func animalSay(speak Speak)  {
    speak.say()
}
​
func main() {
    r :=RDuck{}
    b :=BDuck{}
    animalSay(r)
    animalSay(b)
}
​
// 类型断言
// 当把具体类型传入接口,接口中只定义了部分方法,而无法使用具体类型中的属性和方法,这种情况下使用断言如果断言对了,把接口类型转换为具体类型从而使用类型中的属性和方法。
func test1(a Animal)  {  // 对传入的接口类型断言
    //var dog=d.(Dog)
    dog, ok :=a.(Dog)
    if ok{
        fmt.Println(dog.Name)
        fmt.Println(dog.Lookhome)
    } else {
        fmt.Println("断言失败不是Dog类型")
    }
}
​
func main()  {
    dog :=Dog{Name: "旺财", Age: 1}
    cat :=Cat{Name: "小咪", Age: 2}
    var animal1 Animal
    var animal2 Animal
    animal1=dog
    animal2=cat
    test1(animal1)
    test1(animal2)  // 断言失败
}
​
// 断言类型选择
// 类型选择
func  test(i interface{})  {
    switch obj:=i.(type){
    case Dog:
        obj.Lookhome()
    case Cat:
        fmt.Println("断言传入接口的是Cat类型")
    case string:
        fmt.Println("传入接口的是String类型")
    case int:
        fmt.Println("传入接口的是int类型")
    default:
        fmt.Println("未断言出类型")
    }
}
​
func main()  {
    dog :=Dog{Name: "旺财", Age: 1}
    cat :=Cat{Name: "小咪", Age: 2}
    var animal1 Animal
    var animal2 Animal
    animal1=dog
    animal2=cat
    test(animal1)
    test(animal2)
}