zoukankan      html  css  js  c++  java
  • go 面向对象

    结构体

    创建结构体变量和访问结构体字段

    package main
    
    import "fmt"
    
    //创建结构体变量和访问结构体字段
    type Person struct {
        Name string
        Age int
    }
    
    
    func main(){
        //方式一
        var p1 Person
        p1.Name="牛魔王"
        p1.Age=24
        fmt.Println(p1)
        //方式二
    p2:=Person{"mary",20}
    p2.Name="tome"
    p2.Age=18
    fmt.Println(p2)
    //方式三
    var p3 *Person=new (Person)
    //因为p3是指针,因此赋值方式
        (*p3).Name="smith"//也可以这样写p3.Name="smith2"
        //fmt.Println(*p3)
        p3.Age=100
        fmt.Println(*p3)
        //方式四
        var person *Person=&Person{}//结构体指针
        //person.Age=10和(*person).Age=88效果一样,因为
        (*person).Name="scott"
        person.Name="scott~~~"
        (*person).Age=88
        person.Age=10
    //go编译器底层对person.Name做了转化(*person).Name
    
        fmt.Println(*person)
    
    
    }
    View Code

    结构体在内存中的体现

    0.

    package main
    
    import "fmt"
    
    //struct类型的内存分配机制
    type Person struct{
        Name string
        Age int
    }
    
    
    func main(){
    var p1 Person
    
    p1.Age=10
    p1.Name="小明"
    var p2 *Person=&p1
    fmt.Println((*p2).Age)
    fmt.Println(p2.Age)
    p2.Name="tom~~"
    fmt.Printf("p2.Name=%v p1.Name=%v
    ",p2.Name,p1.Name)
    fmt.Printf("p2.Name=%v p1.Name=%v
    ",(*p2).Name,p1.Name)
    
    fmt.Printf("p1的地址%p
    ",&p1)
    fmt.Printf("p2的地址%p p2的值%
    ",&p2,p2)
    }
    View Code

    字段

    1.在内存中的地址是连续的

    package main
    
    import "fmt"
    
    //结构体所有字段在内存中是连续的
    type Point struct {
        x int
        y int
    
    }
    
    //
    type Rect struct {
        leftUp,rightDown Point
    
    
    }
    type Rect2 struct {
        leftUp,rightDown *Point
    }
    
    func main(){
        r1:=Rect{Point{1,2},Point{3,4}}
        //r1的四个int,在内存中是连续分布的
        //打印地址
        fmt.Printf("r1.leftUp.x地址=%p
    r1.leftUp.y地址=%p
    r1.rightDown.x地址=%p
    r1.rightDown.y地址%p
    ",
            &r1.leftUp.x,&r1.leftUp.y,&r1.rightDown.x,&r1.rightDown.y)
    
        //r2有两个*Point 这两个*Point类型的本身地址也是连续的
        //但他们指向的地址不一定是连续的
        r2:=Rect2{&Point{10,20},&Point{30,40}}
        //打印本身地址
        fmt.Printf("r2.leftUp本身地址=%p r2.rightDown 本身地址=%p 
    ",
            &r2.leftUp,&r2.rightDown)
        //打印指向地址
        //他们指向的地址不一定是连续的
        fmt.Printf("r2.leftUp指向地址=%p r2.rightDown指向地址=%p
    ",
            r2.leftUp,r2.rightDown)
    }
    View Code

    2.结构体是单独定义的类型,与其他类型进行转换时需要有完全相同的字段(名字,个数,类型)

    package main
    
    import "fmt"
    
    //结构体是单独定义的类型,与其他类型进行转换时需要有完全相同的字段(名字,个数,类型)
    type A struct {
        Num int
    }
    type B struct {
        Num int
    }
    
    func main(){
        var a A
        var b B
        a=A(b)//可以转换
        fmt.Println(a,b)
    }
    View Code

    3.结构体进行type重新定义(相当于取别名),golang认为是新的数据类型,但是相互可以强转

    package main
    
    import "fmt"
    
    //结构体进行type重新定义(相当于取别名),golang认为是新的数据类型,但是相互可以强转
    type Student struct {
        Name string
        Age  int
    }
    
    //定义结构体
    type Stu Student
    
    type integer int
    
    func main() {
        var stu1 Student
        var stu2 Stu
        stu2 = Stu(stu1)
        fmt.Println(stu1, stu2)
    
        var i integer=10
        var j int=20
        j=int(i)
        fmt.Println(i,j)
    }
    View Code

    4.struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和饭序列化

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    //struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和饭序列化
    type Monster struct {
        Name string `json:"name"`//`json:"name"`就是struct tag
        Age int `json:"age"`
        Skill string `json:"skill"`
    
    }
    func main(){
        //1.创建一个Moster变量
    monster:=Monster{"牛魔王",500,"芭蕉扇"}
    //2.将Master变量序列化为json格式字串
    //json.Marsha1 函数中使用反射
    jsonStr,err:=json.Marshal(monster)
    if err!=nil{
        fmt.Println("json 处理错误",err)
    }
    //
    fmt.Println("jsonStr",string(jsonStr))
    
    }
    View Code

     匿名结构体

    //匿名结构体
    func main() {
        //匿名函数
        res := func(a, b float64) float64 {
            return math.Pow(a, b)
        }(2, 3)
        fmt.Println(res)
        //匿名结构体
        addr := struct {
            province, city string
        }{"陕西省", "西安市"}
        fmt.Println(addr)
        cat := struct {
            name, color string
            age         int8
        }{
            name:  "绒毛",
            color: "黑白",
            age:   1,
        }
        fmt.Println(cat)
    }
    View Code

    结构体匿名字段

    //结构体匿名字段
    //同一类型的字段只有一个
    type User struct {
        string
        byte
        int8
        float64
    }
    
    func main() {
        //实例化结构体
        user := User{
            "Steven",
            'm',
            35,
            177.5,
        }
        fmt.Println(user)
        //数据依次打印
        fmt.Printf("姓名:%s
    ",user.string)
        fmt.Printf("年龄:%d
    ",user.int8)
        fmt.Printf("身高:%.2f
    ",user.float64)
        fmt.Printf("性别:%c
    ",user.byte)
    }
    View Code

    方法

    1.结构体是值类型,遵循值类型的传递机制

    a

    //结构体类型是值类型,如果改变结构体的变量,可以通过结构体的指针来实现
    
    
    type Circle struct {
        radius float64
    }
    func (c Circle) area() float64{
        return 3.14*c.radius*c.radius
    }
    func (c *Circle) area2() float64{
        (*c).radius=10//等价于c.radius=10
        return 3.14*c.radius*c.radius
    }
    func main(){
        var c Circle
        c.radius=4.0
        res:=c.area()
        fmt.Println("面积是",res)
        //修改结构体的字段
    
        res2:=c.area2()
        fmt.Println(res2)
    
    }
    View Code

    b

    2.使用结构体指针改变结构体变量

    3.自定义struct可以有方法,int,float32也可以有方法

    package main
    
    import "fmt"
    
    //自定义struct可以有方法,int,float32也可以有方法
    type integer int
    
    func (i integer) print(){
    fmt.Println("i=",i)
    }
    
    func (i *integer) change(){
        *i+=1
    }
    
    
    func main(){
    var i integer=10
        i.print()
    i.change()
    fmt.Println("i=",i)
    }
    View Code

     接受者为指针结构体和结构体的区别

    //接受者是指针结构体和普通结构体的区别
    //如果方法的接受者不是指针,实际只是获取一个拷贝,而不能真正改变接受者(结构体)中原来的数据
    
    type Rectangle struct {
        width, height float64
    }
    
    //func
    func (r Rectangle) setValue() {
        fmt.Printf("setValue方法中r的地址:%p
    ", &r)
        r.height = 10
    }
    func (r *Rectangle) setValue2() {
        fmt.Printf("setValue方法中r的地址:%p
    ", &r)
        r.height = 20
    }
    
    func main() {
        r1 := Rectangle{5, 8}
        r2 := r1
        //打印对象的内存地址
        fmt.Printf("r1的地址:%p
    ", &r1)
        fmt.Printf("r1的地址:%p
    ", &r2)
        r1.setValue()
        fmt.Println("r1.height=", r1.height)
        fmt.Println("r2.height=", r2.height)
        r1.setValue2()
        fmt.Println("r1.height=", r1.height)
        fmt.Println("r2.height=", r2.height)
    
    }
    View Code

    4.访问范围控制规则,方法名首字母小写,只能本包访问

    5.如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变凉的String()进行输出

    package main
    
    import "fmt"
    //如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变凉的String()进行输出
    type student struct{
        Name string
        Age int
    }
    
    func (stu *student) String() string{
        str:=fmt.Sprintf("Name=[%v] Age=[%v]",stu.Name,stu.Age)
        fmt.Println("
    string() 我被调用了
    ")
    return str
    }
    
    func main(){
        stu:=student{
            Name:"tom",
            Age:20,
        }
    
        fmt.Println(&stu)
    }
    View Code

    练习

    1.打印矩形

    package main
    
    import "fmt"
    
    type MethodUtils struct {
    
    
    }
    
    func (mu MethodUtils) Print(){
        for i:=1;i<=10;i++{
            for j:=1;j<=8;j++{
                fmt.Print("*")
            }
            fmt.Println()
        }
    }
    
    func (mu MethodUtils) Print2(m int,n int){
        for i:=1;i<=m;i++{
            for j:=1;j<=n;j++{
                fmt.Print("*")
            }
            fmt.Println()
        }
    }
    
    //计算矩形面积
    func (mu MethodUtils) area(len float64,width float64) float64{
        return len*width
    }
    
    //判断一个数是奇数还是偶数
    func (mu *MethodUtils) JudgeNum(num int){
        if num%2==0{
            fmt.Println(num,"是偶数")
        }else{
            fmt.Println(num,"是奇数")
        }
    }
    //根据行列,字符打印
    func (mu *MethodUtils) Print3(n int,m int,key string){
        for i:=1;i<=n;i++{
            for j:=1;j<=m;j++{
                fmt.Print(key)
            }
            fmt.Println()
        }
    }
    func main(){
        var mu MethodUtils
        mu.Print()
        mu.Print2(5,5)
        fmt.Println(mu.area(4,3))
        mu.JudgeNum(4)
        mu.Print3(3,4,"~")
    }
    View Code

    2.计算

    package main
    
    import "fmt"
    
    type Cacuator struct {
        Num1 float64
        Num2 float64
    }
    
    func (calcuator *Cacuator) getSum() float64 {
        return calcuator.Num1 + calcuator.Num2
    }
    
    func (calcuator *Cacuator) getSub() float64 {
        return calcuator.Num1 - calcuator.Num2
    }
    
    //方式二
    func (calcuator *Cacuator) getRes(operator byte) float64 {
        res := 0.0
        switch operator {
        case '+':
            res = calcuator.Num1 - calcuator.Num2
        case '-':
            res = calcuator.Num1 - calcuator.Num2
        case '*':
            res = calcuator.Num1 * calcuator.Num2
        case '/':
            res = calcuator.Num1 / calcuator.Num2
        default:
            fmt.Println("运算符输入错误")
        }
        return res
    }
    View Code

    3.值拷贝和地址拷贝

    package main
    
    import "fmt"
    
    type Person struct {
        Name string
    }
    //决定值拷贝还是地址拷贝看这个方法和哪个类型绑定
    func test01(p Person) {
        fmt.Println(p.Name)
    }
    
    func test02(p *Person) {
        fmt.Println(p.Name)
    }
    
    //对于方法,接受者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以
    func (p Person) test03() {
        p.Name = "jack"
        fmt.Println("test03()=", p.Name)
    }
    func (p *Person) test04() {
        p.Name = "mary"
        fmt.Println("test03()=", p.Name)
    }
    
    func main() {
        p := Person{"tom"}
        test01(p)
        //对于普通函数,接受者为值类型时,不能将指针类型的数据直接传递,反之亦然
        test02(&p)
    
        p.test03()
        fmt.Println("main() p.name=", p.Name)
        (&p).test03() //从形式上传入地址,但本质上仍是值拷贝
        fmt.Println("main() p.name=",p.Name)
    
        (&p).test04()
        fmt.Println("main() p.name=",p.Name)
        p.test04()//等价于(&p).test04(),从形式上石传入值类型,但本质上仍是地址拷贝
    }
    View Code

    应用案例

    1.

    package main
    
    import (
        "fmt"
    )
    
    type Student struct {
        name string
        gender string
        age int
        id int
        score float64
    }
    
    func (student *Student) say() string{
        infoStr:=fmt.Sprintf("student 的信息name=[%v],gender=[%v],age=[%v],id=[%v],score=[%v]",
            student.name,student.gender,student.age,student.id,student.score)
        return infoStr
    }
    
    
    func main(){
    var stu=Student{
        name:"tom",
        gender:"male",
        age:18,
        id:1000,
        score:99.98,
    }
    fmt.Println(stu.say())
    }
    View Code

    2.计算面积

    package main
    
    import "fmt"
    
    type Box struct {
        len    float64
        width  float64
        height float64
    }
    
    func (box *Box) getVolumn() float64 {
        return box.len * box.width * box.height
    }
    
    func main(){
        var box Box
        box.len=1.1
        box.width=2.0
        box.height=3.0
        volumn:=box.getVolumn()
        fmt.Printf("体积为=%2.f",volumn)
    }
    View Code

    3.门票

    package main
    
    import "fmt"
    
    //景区门票案例
    //根据年龄判断价额
    type Visitor struct{
        Name string
        AGe int
    }
    
    func (visitor *Visitor) showPrice(){
        if visitor.AGe>=90||visitor.AGe<=8{
            fmt.Println("考虑到安全,就不要玩了")
            return
        }
    
        if visitor.AGe>18{
            fmt.Printf("游客的名字为%v 年龄为%v 收费为20元
    ",visitor.Name,visitor.AGe)
        }else{
            fmt.Printf("游客的名字为%v 年龄为%v 免费
    ",visitor.Name,visitor.AGe)
        }
    }
    
    func main(){
    var v Visitor
    for{
        fmt.Println("请输入你的名字")
        fmt.Scanln(&v.Name)
        if v.Name=="n"{
            fmt.Println("退出程序")
        }
        fmt.Println("请输入你的年龄")
        fmt.Scanln(&v.AGe)
        v.showPrice()
    }
    
    }
    View Code

    创建结构体实例时,指定字段的值

    package main
    
    import "fmt"
    
    //创建结构体实例时,指定字段的值
    
    type Stu struct{
        Name string
        Age int
    }
    
    func main(){
        //实例化时赋初始值
        var stu1=Stu{"小明",19}
        stu2:=Stu{"小强",20}
        //下面这种方法可以不考虑顺序
        var stu3=Stu{
            Name: "jack",
            Age:  20,
        }
        stu4:=Stu{
            Age:30,
            Name:"mary",
        }
        fmt.Println(stu1,stu2,stu3,stu4)
    
        //方式二
        var stu5 *Stu=&Stu{"小王",20}
        stu6:=&Stu{"小王",39}
        var stu7=&Stu{
            Name:"小东",
            Age:22,
    
        }
        stu8:=&Stu{
            Age:15,
            Name:"rose",
        }
    
        fmt.Println(*stu5,*stu6,*stu7,*stu8)
    }
    View Code

    工厂模式

    mian/main.go

    package main
    
    import (
        "fmt"
        "oop/10.5.3/model"
    )
    //引入首字母小写的字段和方法
    func main(){
        var stu=model.NewStudent("tom",88.8)
        fmt.Println(*stu)
        fmt.Println("name=",stu.Name,"score=",stu.Score)
    }
    View Code

    model/student.go

    package model
    
    type student struct{
        Name string
        Score float64
    }
    func NewStudent(n string,s float64) *student{
        return &student{
            Name:n,
            Score:s,
        }
    }
    View Code

     面向对象三大特性

     面向对象-抽象

    package main
    
    import "fmt"
    
    type Account struct{
        AccountNo string
        Pwd string
        Balance float64
    }
    
    
    //存款
    func (account *Account) Deposite(money float64,pwd string){
        if pwd!=account.Pwd{
            fmt.Println("你输入的密码不正确")
            return
        }
    
        if money<=0{
            fmt.Println("你输入的金额不正确")
            return
        }
        account.Balance+=money
        fmt.Println("存款成功")
    }
    
    //取款
    func (account *Account) WidthDraw(money float64,pwd string){
        if pwd!=account.Pwd{
            fmt.Println("你输入的密码不正确")
            return
        }
        if money<=0||money>account.Balance{
            fmt.Println("金额不正确")
            return
        }
        account.Balance-=money
        fmt.Println("取款成功")
    }
    //查询余额
    func (account *Account) Query(pwd string){
        if pwd!=account.Pwd{
            fmt.Println("密码不正确")
            return
        }
        fmt.Printf("你的账号为%v,余额为%v",account.AccountNo,account.Balance)
    }
    
    
    func main(){
        account:=Account{
            AccountNo:"gs111",
            Pwd:"666666",
            Balance:100.0,
    
        }
    
        account.Query("666666")
    account.Deposite(200.0,"666666")
    }
    View Code

    面向对象-封装

     model/person.go

    package model
    
    
    
    import "fmt"
    
    type person struct {
        Name string
        age int
        sal float64
    }
    //工厂模式,相当于构造函数
    func NewPerson(name string) *person{
        return &person{
            Name:name,
        }
    }
    
    func (p *person) SetAge(age int){
        if age>0&&age<150{
            p.age=age
        }else{
            fmt.Println("年龄范围不正确")
        }
    }
    func (p *person) GetAge() int{
        return p.age
    }
    func (p *person) SetSal(sal float64){
        if sal>=3000&&sal<=30000{
            p.sal=sal
        }else{
            fmt.Println("范围不正确")
        }
    }
    
    func (p *person) GetSal() float64{
        return p.sal
    }
    View Code

    main/main.go

    package main
    
    import (
        "fmt"
        "oop/11.3.6/model"
    )
    
    func main(){
        p:=model.NewPerson("smith")
        p.SetAge(18)
        p.SetSal(5000)
        fmt.Println(p)
        fmt.Println(p.Name,"age=",p.GetAge(),"sal=",p.GetSal())
    }
    View Code

     继承

    基础版

    package main
    
    import "fmt"
    
    //继承
    type Pupil struct{
        Name string
        Age int
        Score int
    }
    //显示成绩
    func (p *Pupil) ShowInfo(){
        fmt.Printf("学生名=%v 年龄=%v 成绩=%v
    ",p.Name,p.Age,p.Score)
    }
    
    func (p *Pupil) SetScore(score int){
        p.Score=score
    }
    
    func (p *Pupil) testig(){
        fmt.Println("考试中...")
    }
    
    
    type Graduate struct {
        Name string
        Age int
        Score int
    }
    func (p *Graduate) ShowInfo(){
        fmt.Printf("学生名=%v,年龄=%v,成绩=%v",p.Name,p.Age,p.Score)
    }
    
    func (p *Graduate) SetScore(score int){
        p.Score=score
    }
    
    func (p *Graduate) testing(){
        fmt.Println("大学生正在考试中。。")
    }
    
    
    func main(){
        var pupil=&Pupil{
            Name:  "tom",
            Age:   10,
        }
        pupil.testig()
        pupil.SetScore(90)
        pupil.ShowInfo()
    }
    View Code

    改进版

    package main
    
    import (
        "fmt"
    )
    
    //改进版
    type Student struct {
        Name string
        Age int
        Score int
    }
    func (stu *Student) ShowInfo(){
        fmt.Printf("学生名=%v,年龄=%v,成绩=%v
    ",stu.Name,stu.Age,stu.Score)
    }
    func (stu *Student) SetScore(score int){
        stu.Score=score
    }
    
    type Pupil struct {
        Student//潜入了Student匿名结构体
    }
    func (p *Pupil) testing(){
        fmt.Println("小学生考试中。。。")
    }
    
    type Graduate struct {
        Student
    }
    
    func (p *Graduate) testing(){
        fmt.Println("大学生正在考试中。。。")
    }
    
    
    func main(){
        pupil:=&Pupil{}
        pupil.Student.Name="tom~"
        pupil.Student.Age=8
        pupil.testing()
        pupil.Student.SetScore(70)
        pupil.Student.ShowInfo()
    
    
        graduate:=&Graduate{}
        graduate.Student.Name="mary~"
        graduate.Student.Age=28
        graduate.testing()
        graduate.Student.SetScore(90)
        graduate.Student.ShowInfo()
    
    }
    View Code

    a

    package main
    
    import (
        "fmt"
    )
    
    type A struct {
        Name string
        age int
    }
    
    func (a *A) SayOk(){
        fmt.Println("A SayOk",a.Name)
    }
    
    func (a *A) hello(){
        fmt.Println("A hello",a.Name)
    }
    
    type B struct{
        A
    }
    func main(){
        var b B
        b.A.Name="tom"
        b.A.age=19
        b.A.hello()
        //也可以如下简化
        b.Name="smith"
        b.age=20
        b.SayOk()
        b.hello()
    }
    View Code

    组合

    type D struct {
      a   A
    }
    
    var d D
    d.a.Name="jack"
    View Code

     例

    package main
    
    import "fmt"
    
    type Goods struct{
        Name string
        Price float64
    
    }
    
    type Brand struct{
        Name string
        Address string
    
    }
    type TV struct {
        Goods
        Brand
    
    }
    
    type TV2 struct {
        *Goods
        *Brand
    }
    
    func main(){
        tv:=TV{Goods{"电视机001",5000.99},Brand{"海尔","山东"}}
    tv2:=TV{
        Goods: Goods{
            Price:5000.99,
            Name:"电视机002",
        },
        Brand: Brand{
                Name:"夏普",
                Address:"北京",
        },
    }
    
    fmt.Println("tv",tv)
    fmt.Println("tv2",tv2)
    tv3:=TV2{&Goods{"电视机003",7000.99},&Brand{"创维","河南"}}
    
    tv4:=TV2{&Goods{Name:"电视机004",Price:9000.88},&Brand{Name:"长虹",Address:"四川"}}
    fmt.Println("tv3",*tv3.Goods,*tv3.Brand)
    fmt.Println("tv4",*tv4.Goods,*tv4.Brand)
    
    
    }
    View Code

     类型作为字段

    package main
    
    import "fmt"
    
    type Monster struct {
        Name string
        Age int
    }
    
    type E struct{
        Monster
        int
        n int
    }
    
    func main(){
        var e E
        e.Name="狐狸精"
        e.Age=300
        e.int=20
        e.n=40
        fmt.Println("e=",e)
    }
    /*
    1.一个结构体同类型的匿名字段只能有一个。
    2.如果需要多个,则必须给int字段指定名字
    
    */
    View Code

     接口

    初识

    package main
    
    import "fmt"
    
    //接口
    
    type Usb interface{
        Start()
        Stop()
    }
    
    type Phone struct{
    
    }
    
    func (p Phone) Start(){
        fmt.Println("手机开始工作了")
    }
    
    func (p Phone) Stop(){
        fmt.Println("手机停止工作了")
    }
    
    type Camera struct {
    
    }
    
    func (c Camera) Start(){
        fmt.Println("相机开始工作。。。")
    }
    
    func (c Camera) Stop(){
        fmt.Println("相机停止工作。。。")
    }
    
    type Computer struct{
    
    }
    
    func (c Computer) Working(usb Usb){
        usb.Start()
        usb.Stop()
    }
    
    func main(){
        computer:=Computer{}
        phone:=Phone{}
        camera:=Camera{}
        computer.Working(phone)
        computer.Working(camera)
    }
    View Code

    结构体本身不创建实例,但可以指向一个实现了该接口的自定义类型变量

    package main
    
    import "fmt"
    
    //结构体本身不创建实例,但可以指向一个实现了该接口的自定义类型变量
    type AInterface interface{
        Say()
    }
    type Stu struct{
        Name string
    }
    func (stu Stu) Say(){
        fmt.Println("stu say()")
    }
    
    
    func main(){
        var stu Stu//结构体变量实现了Say(),实现了AInterface
        var a AInterface=stu
        a.Say()
    }
    View Code

     一个自定义类型可以实现多个接口

    package main
    
    import "fmt"
    
    //一个自定义类型可以实现多个接口
    type Ainterface interface{
        Say()
    }
    type BInterface interface {
        Hello()
    }
    
    type Monster struct{
    
    }
    func (m Monster) Hello(){
        fmt.Println("Monster Hello()~~")
    }
    func (m Monster) Say(){
        fmt.Println("Monster Say()~~")
    }
    func main(){
        var monster Monster
        var a2 Ainterface=monster
        var b2 BInterface=monster
        a2.Say()
        b2.Hello()
    }
    View Code

    接口中不能有变量

    实现接口时,继承的接口也必须实现

    内置方法排序

    package main
    
    import (
        "fmt"
        "math/rand"
        "sort"
    )
    
    //最佳实践
    type Hero struct{
        Name string
        Age int
    
    }
    type HeroSlice []Hero
    
    func (hs HeroSlice) Len() int{
        return len(hs)
    }
    
    func (hs HeroSlice) Less(i,j int)bool{
        return hs[i].Age<hs[j].Age
    }
    
    func (hs HeroSlice) Swap(i,j int){
        hs[i],hs[j]=hs[j],hs[i]
    }
    type Student struct{
        Name string
        Age int
        Score float64
    }
    
    func main(){
        var intSlice=[]int{0,-1,10,7,90}
        sort.Ints(intSlice)
        fmt.Println(intSlice)
    
        var heroes HeroSlice
        for i:=0;i<10;i++{
            hero:=Hero{
                Name: fmt.Sprintf("英雄%d",rand.Intn(100)),
                Age:  rand.Intn(100),
            }
            heroes=append(heroes,hero)
        }
        for _,v:=range heroes{
            fmt.Println(v)
        }
    
        //调用sort
        sort.Sort(heroes)
        fmt.Println("----排序后----")
        for _,v :=range heroes{
            fmt.Println(v)
        }
        i:=10
        j:=20
        i,j=j,i
        fmt.Println("i=",i,"j=",j)
    }
    View Code

     接口实现多态

    package main
    
    import "fmt"
    
    //接口体现多态的两种形式,多态参数,多态数组
    type Usb interface{
        Start()
        Stop()
    }
    type Phone struct {
        name string
    }
    
    func (p Phone) Start(){
        fmt.Println("手机开始工作。。。")
    }
    
    func (p Phone) Stop(){
        fmt.Println("手机停止工作")
    }
    
    type Camera struct {
        name string
    }
    
    func (c Camera) Start(){
        fmt.Println("相机开始工作。。。")
    }
    
    func (c Camera) Stop(){
        fmt.Println("相机停止工作...")
    }
    
    func main(){
        var usbArr[3]Usb
        usbArr[0]=Phone{"vivo"}
        usbArr[1]=Phone{"小米"}
        usbArr[2]=Phone{"尼康"}
        fmt.Println(usbArr)
    }
    View Code

    鸭子类型

    如果一个动物,走起来像鸭子,叫起来像鸭子,那么它就是鸭子

    package main
    
    import "fmt"
    
    //鸭子类型
    //定义接口类型
    type ISayHello interface {
        SayHello() string
    }
    
    //
    type Duck struct {
        name string
    }
    type Person struct {
        name string
    }
    
    func (d Duck) SayHello() string {
        return d.name + "叫 ga ga ga"
    }
    func (p Person) SayHello() string {
        return p.name + "说 Hello"
    }
    
    func main() {
        //定义实现接口的对象
        duck := Duck{"yaya"}
        person := Person{"Steven"}
        fmt.Println(duck.SayHello())
        fmt.Println(person.SayHello())
        fmt.Println("-------")
        //定义接口类型的变量
        var i ISayHello
        i = duck
        fmt.Printf("%T,%v,%p 
    ", i, i, &i)
        fmt.Println(i.SayHello())
        i = person
        fmt.Printf("%T,%v,%p
    ", i, i, &i)
        fmt.Println(i.SayHello())
    }
    View Code

    类型断言

    由于接口是一般类型,不知具体类型,就需要使用类型断言

    1

    package main
    
    import "fmt"
    
    //解决将接口变量赋值给自定义类型的变量
    //类型断言
    type Point struct {
        x int
        y int
    }
    
    func main() {
        var a interface{}
        var point Point = Point{1, 2}
        a = point //实现接口
        var b Point
        b = a.(Point)//类型断言
        fmt.Println(b)
    }
    View Code

    2.

    package main
    
    import "fmt"
    
    func main(){
        var x interface{}
        var b2 float32=1.1
        x=b2
        y:=x.(float32)
        fmt.Printf("y的类型是%T,值=%v",y,y)
    }
    View Code

    3.类型断言,带检测

    package main
    
    import "fmt"
    
    func main(){
        var x interface{}
        var b2 float32=2.1
        x=b2
    
        if y,ok:=x.(float32);ok{
            fmt.Println("convert success")
        fmt.Printf("type=%T,val=%v",y,y)
        }else{
            fmt.Println("convert fail")
        }
        fmt.Println("继续执行。。。")
    
    
    
        //
    }
    View Code

    最佳实践:结构体断言,执行方法

    package main
    
    import (
        "fmt"
    )
    
    //类型断言最佳实践1
    type Usb interface {
        Start()
        Stop()
    }
    
    type Phone struct {
        name string
    }
    
    func (p Phone) Start() {
        fmt.Println("手机开始工作。。。")
    }
    
    func (p Phone) Stop() {
        fmt.Println("手机停止。。")
    }
    func (p Phone) Call() {
        fmt.Println("手机 在打电话")
    }
    
    type Camera struct {
        name string
    }
    
    func (p Camera) Start() {
        fmt.Println("相机开始工作。。。")
    }
    
    func (p Camera) Stop() {
        fmt.Println("相机停止。。")
    }
    
    type Computer struct {
    }
    
    func (computer Computer) Working(usb Usb) {
        usb.Start()
        //类型断言,注意体会
        if phone, ok := usb.(Phone); ok {
            phone.Call()
        }
        usb.Stop()
    }
    
    func main() {
        var usbArr [3]Usb
        usbArr[0] = Phone{"vivo"}
        usbArr[1] = Phone{"小米"}
        usbArr[2] = Camera{"尼康"}
        //phone 有一个特殊方法,如果是手机需要调用
        var computer Computer
        for _, v := range usbArr {
            computer.Working(v)
            fmt.Println()
        }
    }
    View Code

     类型断言2:

     判断输入的参数是什么类型

    package main
    
    import "fmt"
    
    //类型断言最佳实践2
    //编写一个函数,可以判断输入的参数是什么类型
    func TypeJudge(items... interface{}){
        for index,x:=range items{
            switch x.(type){
            case bool:
                fmt.Printf("第%v个参数是bool类型,值是%v
    ",index,x)
            case float32:
                fmt.Printf("第%v个参数是float32类型,值是%v
    ",index,x)
            case float64:
                fmt.Printf("第%v个参数是float64类型,值是%v
    ",index,x)
            case int,int32,int64:
                fmt.Printf("第%v个参数是int,int32,int64类型,值是%v
    ",index,x)
            case string:
                fmt.Printf("第%v个参数是string类型,值是%v
    ",index,x)
            default:
                fmt.Printf("第%v个参数是类型 不确定,值是%v
    ",index,x)
            }
        }
    }
    
    
    func main(){
        var n1 float32=1.1
        var n2 float64=2.3
        var n3 int32=30
        var name string="tom"
        address:="北京"
        n4:=300
        TypeJudge(n1,n2,n3,name,address,n4)
    }
    View Code

    类型断言3

    package main
    
    import "fmt"
    
    
    type Student struct {
    
    }
    //类型断言最佳实践2
    //编写一个函数,可以判断输入的参数是什么类型
    func TypeJudge(items... interface{}){
        for index,x:=range items{
            switch x.(type){
            case bool:
                fmt.Printf("第%v个参数是bool类型,值是%v
    ",index,x)
            case float32:
                fmt.Printf("第%v个参数是float32类型,值是%v
    ",index,x)
            case float64:
                fmt.Printf("第%v个参数是float64类型,值是%v
    ",index,x)
            case int,int32,int64:
                fmt.Printf("第%v个参数是int,int32,int64类型,值是%v
    ",index,x)
            case string:
                fmt.Printf("第%v个参数是string类型,值是%v
    ",index,x)
            case Student:
                fmt.Printf("第%v个参数是Student类型,值是%v
    ",index,x)
            case *Student:
                fmt.Printf("第%v个参数是*Student类型,值是%v
    ",index,x)
            default:
                fmt.Printf("第%v个参数是类型 不确定,值是%v
    ",index,x)
            }
        }
    }
    
    
    func main(){
        var n1 float32=1.1
        var n2 float64=2.3
        var n3 int32=30
        var name string="tom"
        address:="北京"
        n4:=300
        var s1 Student
        var s2 *Student
        TypeJudge(n1,n2,n3,name,address,n4,s1,s2)
    }
    View Code

    记账案例面向过程

    package main
    import (
        "fmt"
    )
    func main() {
        //声明一个变量,保存接收用户输入的选项
        key := ""
        //声明一个变量,控制是否退出for
        loop := true
    
        //定义账户的余额 []
        balance := 10000.0
        //每次收支的金额
        money := 0.0
        //每次收支的说明
        note := ""
        //定义个变量,记录是否有收支的行为
        flag := false
        //收支的详情使用字符串来记录
        //当有收支时,只需要对details 进行拼接处理即可
        details := "收支	账户金额	收支金额	说    明"
        //显示这个主菜单
        for {
            fmt.Println("
    -----------------家庭收支记账软件-----------------")
            fmt.Println("                  1 收支明细")
            fmt.Println("                  2 登记收入")
            fmt.Println("                  3 登记支出")
            fmt.Println("                  4 退出软件")
            fmt.Print("请选择(1-4):")
            fmt.Scanln(&key)
    
            switch key {
                case "1":
                    fmt.Println("-----------------当前收支明细记录-----------------")
                    if flag {
                        fmt.Println(details)
                    } else {
                        fmt.Println("当前没有收支明细... 来一笔吧!")
                    }
                    
                case "2":
                    fmt.Println("本次收入金额:")
                    fmt.Scanln(&money)
                    balance += money // 修改账户余额
                    fmt.Println("本次收入说明:")
                    fmt.Scanln(&note)
                    //将这个收入情况,拼接到details变量
                    //收入    11000           1000            有人发红包
                    details += fmt.Sprintf("
    收入	%v	%v	%v", balance, money, note)
                    flag = true
    
                case "3":
                    fmt.Println("本次支出金额:")
                    fmt.Scanln(&money)
                    //这里需要做一个必要的判断
                    if money > balance {
                        fmt.Println("余额的金额不足")
                        break
                    }
                    balance -= money
                    fmt.Println("本次支出说明:")
                    fmt.Scanln(&note)
                    details += fmt.Sprintf("
    支出	%v	%v	%v", balance, money, note)
                    flag = true
                case "4":
                    fmt.Println("你确定要退出吗? y/n")
                    choice := ""
                    for {
    
                        fmt.Scanln(&choice)
                        if choice == "y" || choice == "n" {
                            break
                        }
                        fmt.Println("你的输入有误,请重新输入 y/n")
                    }
    
                    if choice == "y" {
                        loop = false
                    }
                default :
                    fmt.Println("请输入正确的选项..")        
            }
    
            if !loop {
                break 
            }
        }
        fmt.Println("你退出家庭记账软件的使用...")
    }
    View Code

    记账案例面向对象

    utils/familyAccount.go

    package utils
    import (
        "fmt"
    )
    
    type FamilyAccount struct {
        //声明必须的字段.
    
        //声明一个字段,保存接收用户输入的选项
        key  string
        //声明一个字段,控制是否退出for
        loop bool
        //定义账户的余额 []
        balance float64
        //每次收支的金额
        money float64
        //每次收支的说明
        note string
        //定义个字段,记录是否有收支的行为
        flag bool
        //收支的详情使用字符串来记录
        //当有收支时,只需要对details 进行拼接处理即可
        details string
    }
    
    //编写要给工厂模式的构造方法,返回一个*FamilyAccount实例
    func NewFamilyAccount() *FamilyAccount { 
    
        return &FamilyAccount{
            key : "",
            loop : true,
            balance : 10000.0,
            money : 0.0,
            note : "",
            flag : false,
            details : "收支	账户金额	收支金额	说    明",
        }
    
    } 
    
    //将显示明细写成一个方法
    func (this *FamilyAccount) showDetails() {
        fmt.Println("-----------------当前收支明细记录-----------------")
        if this.flag {
            fmt.Println(this.details)
        } else {
            fmt.Println("当前没有收支明细... 来一笔吧!")
        }
    } 
    
    //将登记收入写成一个方法,和*FamilyAccount绑定
    func (this *FamilyAccount) income() {
        
        fmt.Println("本次收入金额:")
        fmt.Scanln(&this.money)
        this.balance += this.money // 修改账户余额
        fmt.Println("本次收入说明:")
        fmt.Scanln(&this.note)
        //将这个收入情况,拼接到details变量
        //收入    11000           1000            有人发红包
        this.details += fmt.Sprintf("
    收入	%v	%v	%v", this.balance, this.money, this.note)
        this.flag = true
    }
    
    //将登记支出写成一个方法,和*FamilyAccount绑定
    func (this *FamilyAccount) pay() {
        fmt.Println("本次支出金额:")
        fmt.Scanln(&this.money)
        //这里需要做一个必要的判断
        if this.money > this.balance {
            fmt.Println("余额的金额不足")
            //break
        }
        this.balance -= this.money
        fmt.Println("本次支出说明:")
        fmt.Scanln(&this.note)
        this.details += fmt.Sprintf("
    支出	%v	%v	%v", this.balance, this.money, this.note)
        this.flag = true
    }
    
    //将退出系统写成一个方法,和*FamilyAccount绑定
    func (this *FamilyAccount) exit() {
    
        fmt.Println("你确定要退出吗? y/n")
        choice := ""
        for {
    
            fmt.Scanln(&choice)
            if choice == "y" || choice == "n" {
                break
            }
            fmt.Println("你的输入有误,请重新输入 y/n")
        }
    
        if choice == "y" {
            this.loop = false
        }
    }
    
    
    //给该结构体绑定相应的方法
    //显示主菜单
    func (this *FamilyAccount) MainMenu() {
    
        for {
            fmt.Println("
    -----------------家庭收支记账软件-----------------")
            fmt.Println("                  1 收支明细")
            fmt.Println("                  2 登记收入")
            fmt.Println("                  3 登记支出")
            fmt.Println("                  4 退出软件")
            fmt.Print("请选择(1-4):")
            fmt.Scanln(&this.key)
            switch this.key {
                case "1":
                    this.showDetails()
                case "2":
                    this.income()
                case "3":
                    this.pay()
                case "4":
                    this.exit()
                default :
                    fmt.Println("请输入正确的选项..")        
            }
    
            if !this.loop {
                break 
            }
    
        }
    }
    View Code

    main/main.go

    package main
    import (
        "go_code/familyaccount/utils"
        "fmt"
    )
    func main() {
    
        fmt.Println("这个是面向对象的方式完成~~")
        utils.NewFamilyAccount().MainMenu() //思路非常清晰
    }
    View Code

    客户管理系统

    model/customer.go

    package model
    
    import (
        "fmt"
    )
    
    type Customer struct {
        Id int
        Name string
        Gender string
        Age int
        Phone string
        Email string
    }
    
    //获取一个Customer
    func NewCustomer(id int, name string, gender string, age int, 
        phone string, email string) *Customer {
        return &Customer{
            Id : id,
            Name : name,
            Gender : gender,
            Age : age,
            Phone : phone,
            Email : email,
        }
    }
    
    //获取一个Customer, 不提供id
    func NewCustomer2(name string, gender string, age int, 
        phone string, email string) *Customer {
        return &Customer{
            Name : name,
            Gender : gender,
            Age : age,
            Phone : phone,
            Email : email,
        }
    }
    
    //返回Customer的信息
    func (this *Customer) GetInfo() string {
    
        info := fmt.Sprintf("%v	%v	%v	%v	%v	%v", this.Id, this.Name, this.Gender, 
            this.Age, this.Phone, this.Email)
        return info
    }
    View Code

    service/customerService.go

    package service
    
    import (
        _ "fmt"
        "go_code/customer/model"
    )
    
    type CustomerService struct {
        //定义一个客户切片,可以存放客户信息
        customers []*model.Customer
        //定义客户的实际个数
        customerNum int
    }
    
    //先创建一个Customer对象,放到 CustomerService的Customers切片中
    //作为测试数据
    func NewCustomerService() *CustomerService {
    
        customerService := &CustomerService{}
    
        //customerService.customers = make([]model.Customer, 1)
        customerService.customerNum = 1
        customer := model.NewCustomer(1, "张三", "",
            10, "999", "zs@sohu.com")
        customerService.customers = append(customerService.customers, customer)
    
        return customerService
    }
    
    //返回客户的信息数组
    
    func (this *CustomerService) List()  []*model.Customer {
        return this.customers
    }
    
    //完成添加客户的功能
    func (this *CustomerService) Add(customer *model.Customer) bool {
    
        this.customerNum++
        //这时我们可以这个customer一个id
        customer.Id = this.customerNum
        this.customers = append(this.customers, customer)
        
        return true
        
    }
    
    
    //删除一个客户
    func (this *CustomerService) Delete(id int) bool {
    
        //先根据id去得到该id的客户对应元素下标
        index := this.FindById(id)
        
        if index == -1 {
            return false
        }
        //找到,删除切片对应的index的元素
        this.customers = append(this.customers[:index], 
            this.customers[index+1:]...)
        //this.customerNum--
        return true
        
    }
    
    //先根据id去得到该id的客户对应元素下标
    //如果找到就返回对应的下标,如果找不到,我们返回-1
    func (this *CustomerService) FindById(id int) int {
        index := -1
        for i := 0; i < this.customerNum; i++ {
            if this.customers[i].Id == id {
                index = i
                break
            }
        }
        return index
    }
    View Code

    view/main.go

    package main
    
    //引入包
    import (
        "fmt"
        "go_code/customer/service"
        "go_code/customer/model"
    )
    
    type CustomerView struct {
    
        //定义一个字段,控制菜单显示是否退出
        loop bool
        //定义一个字段,接收用户输入
        key string
        //定义一个CustomerService 字段,主要用于完成对客户信息的各种操作。
        customerService *service.CustomerService
    }
    
    //显示主菜单
    //    -----------------客户信息管理软件-----------------
    //
    //    1 添 加 客 户
    //    2 修 改 客 户
    //    3 删 除 客 户
    //    4 客 户 列 表
    //    5 退           出
    //
    //    请选择(1-5):_
    
    func (this *CustomerView) mainMenu() {
    
        for {
    
            fmt.Println("-----------------客户信息管理软件-----------------")
            fmt.Println();
            fmt.Println("                 1 添 加 客 户")
            fmt.Println("                 2 修 改 客 户")
            fmt.Println("                 3 删 除 客 户")
            fmt.Println("                 4 客 户 列 表")
            fmt.Println("                 5 退          出")
            fmt.Print("请选择(1-5):")
            fmt.Scanln(&this.key)
    
            switch (this.key) {
            case "1":
                this.add()
            case "2":
                //同学们自己加入
            case "3":
                this.delete()
            case "4":
                //调用方法显示客户信息
                this.list()
            case "5":
                this.loop = false
            default:
                fmt.Println("输入错误");
            }
    
            if !this.loop {
                break
            }
    
        }
    }
    
    //编写一个方法,可以显示客户信息
    //    ---------------------------客户列表---------------------------
    //    编号  姓名       性别    年龄   电话            邮箱
    //     1    张三       男      30     010-56253825   abc@email.com
    //     2    李四       女      23     010-56253825    lisi@ibm.com
    //     3    王芳       女      26     010-56253825   wang@163.com
    //    -------------------------客户列表完成-------------------------
    
    func (this *CustomerView) list() {
    
        //调用 customerService 获取到 客户信息切片
        customerList := this.customerService.List()
    
        //显示
        fmt.Println("---------------------------客户列表---------------------------")
        fmt.Println("编号	姓名	性别	年龄	电话	邮箱")
    
        //遍历
        for i := 0; i < len(customerList); i++ {
            fmt.Println(customerList[i].GetInfo())
        }
        fmt.Println("---------------------------客户列表完成---------------------------")
        
    }
    
    //添加客户
    //    ---------------------添加客户---------------------
    //    姓名:张三
    //    性别:男
    //    年龄:30
    //    电话:010-56253825
    //    邮箱:zhang@abc.com
    //    ---------------------添加完成---------------------
    
    func (this *CustomerView) add() {
    
        fmt.Println("---------------------添加客户---------------------")
        fmt.Println("姓名:")
        name := ""
        fmt.Scanln(&name)
        fmt.Println("性别:")
        gender := ""
        fmt.Scanln(&gender)
        age := 0
        fmt.Println("年龄:")
        fmt.Scanln(&age)
        fmt.Println("电话:");
        phone := ""
        fmt.Scanln(&phone)
        fmt.Println("邮箱:");
        email := ""
        fmt.Scanln(&email)
    
        //根据用户输入,创建一个Customer对象
        customer := model.NewCustomer2(name, gender, age, phone, email)
        
        if(this.customerService.Add(customer)){
            fmt.Println("---------------------添加客户成功---------------------");
        }else{
            fmt.Println("---------------------添加客户失败---------------------");
        }
    }
    
    //删除
    //    ---------------------删除客户---------------------
    //    请选择待删除客户编号(-1退出):1
    //    确认是否删除(Y/N):y
    //    ---------------------删除完成---------------------
    
    func (this *CustomerView) delete() {
    
        fmt.Println("---------------------删除客户---------------------")
        fmt.Println("请选择待删除客户编号(-1退出)")
        id := 0
        fmt.Scanln(&id)
        //如果用户输入-1
        if id == -1 {
            return
        }
        fmt.Println("确认是否删除(Y/N):")
    
        choice := ""
        fmt.Scanln(&choice) // 可以
        
        if choice == "Y" || choice == "y"  {
            
            if this.customerService.Delete(id) {
                fmt.Println("---------------------删除完成---------------------")
            } else {
                fmt.Println("---------------------删除失败,id不存在---------------------")
            }
        }
    } 
    
    
    func main() {
    
        customerView := CustomerView{
            loop : true,
        }
        customerView.customerService = service.NewCustomerService()
        customerView.mainMenu()
    }
    View Code

     反射

    反射的基本介绍
    1.反射可以在运行时,动态获取变量各种信息,比如变量的类型(type),类别(kind)
    2.如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段,方法)
    3.通过反射可以改变变量的值,可以调用关联的方法
    4.使用反射需要import("reflect")

     1.反射的使用场景

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    //反射的使用场景
    type Monster struct{
        Name string `json:"name"`
        Age int `json:"age"`
        Sal float64 `json:"sal"`
        Sex string `json:"sex"`
    }
    
    func main(){
        m:=Monster{
            Name: "玉兔精",
            Age:  20,
            Sal:  11663.12,
            Sex:  "female",
        }
    
        data,_:=json.Marshal(m)
    
        fmt.Println("json result:",string(data))
    }
    View Code

    2.演示类型断言

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    /*
    演示对基本数据类型,interface{},reflect.Value),进行反射的基本操作
    
    */
    
    func reflectTest01(b interface{}){
        //通过反射获取传入的变量的type,kind,值
        //1.先获取到reflect.TypeOf
        rTyp:=reflect.TypeOf(b)
        fmt.Println("rType=",rTyp)
    //kind为int
        //2.获取到refect.Value
        rVal:=reflect.ValueOf(b)
    
        n2:=2+rVal.Int()//转为基础类型int
        fmt.Println("n2=",n2)
        fmt.Printf("rVal=%v,rVal Type=%T
    ",rVal,rTyp)
        //下面我们将rVal转成interface{}
        iV:=rVal.Interface()
        //将interface{}通过断言转成需要的类型
        num2:=iV.(int)
        fmt.Printf("num2=%v  num2 类型=%T
    ",num2,num2)
    }
    
    //专门研究反射[对结构体的反射]
    func reflectTest02(b interface{}){
        //通过反射传入的变量type,kind,值
        //先获取到reflect.Type
        rType:=reflect.TypeOf(b)
        fmt.Println("rType=",rType)
        //2.获取reflect.Value
        rVal:=reflect.ValueOf(b)
        //下面我们将rVal转成interface{}
        iV:=rVal.Interface()
        fmt.Printf("iV=%v iv type=%T
    ",iV,iV)
        //将interface{}通过断言转成需要的类型
        //这里,使用带检测的类型断言
        stu,ok:=iV.(Student)
        if ok{
            fmt.Printf("stu.Name=%v
    ",stu.Name)
        }
    }
    type Student struct {
        Name string
        Age int
    }
    
    func main(){
    //var num int=100
    //reflectTest01(num)
    //2.定义一个student的实例
    stu:=Student{
        Name:"tom",
        Age:20,
    }
    reflectTest02(stu)
    }
    View Code

    3.改变传入变量的值

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    /*
    改变传入变量的值
    
    
    */
    func testInt(b interface{}){
        //获取reflect.ValueOf的值
        val:=reflect.ValueOf(b)
        fmt.Printf("val type=%T
    ",val)
        //设置值
        val.Elem().SetInt(110)
        fmt.Printf("val=%v
    ",val)
    }
    
    func main(){
        var num int=20
        testInt(&num)
        fmt.Println("num=",num)
    }
    View Code

    4.指针修改变量和反射修改变量对比

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    /*
    改变传入变量的值
    
    
    */
    //方式一
    func update1(str *string) {
    //传入指针
        fs := reflect.ValueOf(str)
        //通过指针修改值
        fs.Elem().SetString("jack")
    }
    //方式二
    func update2(str *string) {
        //等价于下面的代码
        *str = "rose"
    }
    func main() {
        var str string = "tom"
        update1(&str)
        fmt.Printf("update1()=%v
    ", str)
        update2(&str)
        fmt.Printf("update2()=%v
    ", str)
    }
    View Code

    5.结构体使用反射获取方法,字段

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    /*
    使用反射来遍历结构体字段,调整结构体的方法,并获取结构体标签的值
    
    */
    //
    type Monster struct {
        Name  string `json:"name"`
        Age   int   `json:"age"`
        Score float32 `json:"score"`
        Sex   string
    }
    
    //返回两个数的和
    func (s Monster) GetSum(n1, n2 int) int {
        return n1 + n2
    }
    
    //接收四个值,给s赋值
    func (s Monster) Set(name string, age int, score float32, sex string) {
        s.Name = name
        s.Age = age
        s.Score = score
        s.Sex = sex
    }
    
    //显示s值
    func (s Monster) Print() {
        fmt.Println("---start---")
        fmt.Println(s)
        fmt.Println("---end---")
    }
    
    func TestStruct(a interface{}) {
        //获取reflect.Type类型
        typ := reflect.TypeOf(a)
        //获取reflect.Value
        val := reflect.ValueOf(a)
        //获取到a对应的类别
        kd := val.Kind()
        fmt.Printf("kind type=%T,kd=%v
    ",kd,kd)//结构类别
        fmt.Printf("a type=%T,a=%v
    ",a,a)//具体定义类型
        fmt.Printf("%v
    ",reflect.Struct)
        //如果传入的不是struct,就退出
        if kd != reflect.Struct {
            fmt.Println("expect struct")
            return
        }
        //获取该结构体有几个字段
        num := val.NumField()
        fmt.Printf("struct has %d fields
    ", num) //4
        //遍历结构体所有字段
        for i := 0; i < num; i++ {
            fmt.Printf("Field %d:值为=%v
    ", i,val.Field(i))
            //获取到结构体的标签,注意前面通过reflect.Type来获取tag标签的值
            tagVal := typ.Field(i).Tag.Get("json")
            //如果该字段于tag标签就显示,否则就不显示
            if tagVal != "" {
                fmt.Printf("Field %d:tag为=%v
    ", i, tagVal)
            }
        }
        //获取该结构体有多少个方法
        numOfMethod := val.NumMethod()
        fmt.Printf("struct has %d methods
    ", numOfMethod)
        //var params []reflect.Value
        //方法的排序默认是按照函数名的排序(ASCII码)
        val.Method(1).Call(nil) //获取到第三个方法调用它
        //调用结构体的第一个方法 Method(0)
        var params []reflect.Value //声明了 []reflect.Value
        params = append(params, reflect.ValueOf(10))
        params = append(params, reflect.ValueOf(40))
        res := val.Method(0).Call(params) //传入的参数是 []reflect.Value 返回[] reflect.Value
        fmt.Println("res=", res[0].Int()) //返回结果是[]reflect.Value
    
    }
    
    func main() {
        var a Monster = Monster{
            Name:  "黄鼠狼精",
            Age:   400,
            Score: 30.8,
        }
        TestStruct(a)
    }
    View Code

    6.

     7.

    8.

    9.

    。。。。

  • 相关阅读:
    解决nginx到后端服务器Connection: close问题
    浅析C#中 ConcurrentDictionary的实现
    Jekins部署.net站点
    vs2017与docker
    折腾docker安装笔记
    SQL Server Profiler 跟踪sql小技巧
    C#定时任务的偷懒实现
    Swashbuckle一个webapi调试利器
    断点续传一些方案的整理
    MySQL 常用命令(4)------mysqladmin命令详解
  • 原文地址:https://www.cnblogs.com/huay/p/12145323.html
Copyright © 2011-2022 走看看