zoukankan      html  css  js  c++  java
  • 20200326 指针结构体方法与接口

    昨日回顾

    // swtich 数组切片 map
    
    // 1 switch (作为if else的另一种尝试)
              /*
              swtich 变量 {
                case 1,5:
                  代码
                case 2,6:
                  代码
                defult:
                  代码
              }
    
              swtich  {
                case 条件:
                  代码
                case 条件:
                  代码
                  Fallthrough
                defult:
                  代码
              }
              */
    //2 数组
     -内存中连续的存储空间,数组大小是固定的
    	-var a [8]int=[8]int{1,2}
    	-var a [8]int=[8]int{1:99}
    	-a[2]
    	-数组是值类型
    	-数组长度 len
    	-数组的遍历(两种)
          -for i,v:=range a{
                  ---i:索引
                  ---v:值
          }
    	-多维数组
    			-var a [2][3]int=[2][3]int{{1,2,3},{4,5,6}}
    			-a[0][1]
    //3 切片:本身不存储数据,对底层数组的引用
    	-基于底层数组创建
    			var a [8]int=[8]int{1,2}
    			b:=a[:]
    			b:=make([]int,3,5)
    			b:=[]int{1,2}
    	-长度和容量
    	-使用 b[100]  //程序执行,如果越界,就报错
    	-引用类型
    	-追加 append
    	-循环  range
    	-多维切片
    	-切片的数据结构  a[4]
    			{
            指向数组的指针
            长度
            容量、
          }
    
    //4 map:key value存储
    	-定义 var a map[key的类型]value的类型
    	-var a map[key的类型][]map[int]string
    	-var a map[key的类型]对象
    	-a[key]
    	-可能为空值,不会报错
    	-判断key是否存在
        if _,ok:=a[999];!ok{
          fmt.Println("不存在")
        }
    	-map的长度 len
    	-循环map
          for k,v:=range a{
              k:key
              v:value
          }
    	-map是引用类型 (空值为nil,当参数传递会修改原来的值)
    	-相等性(只能跟nil比较)
    
    
    
    
    //补充:自动化运维
    	-资产收集20台服务器
    	-项目日志:echars 
    	-批量执行命令,批量安装软件,代码自动发布,自动下线
    

    go语言进阶

    一. 指针 &*

    指针是一种存储 变量内存地址 的变量

    • 取一个变量的地址: & 取地址符号
    • 如果在类型前面加*,表示指向这个类型的指针
    • 在指针变量前加*,表示解引用(反解),通过地址拿到值

    1. 指针的定义

    func main(){
        var b=156
        // 把b内存地址赋值给a这个指针
        // 取一个变量的地址: & 取地址符号
        
        // 如果在类型前面加*,表示指向这个类型的指针
        var a *int = &b
        // var c *string =&b  int类型不能赋值给字符串类型的指针
        // a :=&b
        fmt.Println(a)
    }
    

    2.指针的零值

    var b int 
    fmt.Println(b)   // nil
    

    3. 指针的解引用

    拿到地址指向的值

    var b = 156
    a:=&b
    fmt.Println(a)
    // 指针a指向的值: 解引用(反解)
    fmt.Println(*a)
    

    4. 向该函数传递指针参数

    func(){
        var b = 126
        fmt.Println(b)	//156
        test(&b)
        fmt.Println(*b)	//166
    }
    
    func test(b *int){
        //解引用,然后操作 b是一个指针
        *b++	//指针传过来地址,修改了原来的数据
        fmt.Println(*b)	//166
    }
    

    5. 不要向函数传递数组的指针,而应该使用切片

    • 切片较数组内存占用小
    • 传递类型不会因数组大小而更改
    func main() {
        var a[3]int = [3]int{3,4,5}
        //写一个函数,传入数组,改掉原来的数组
        test(&a)    // 传入变量的地址
        
        
        // 向函数传递切片 (推荐使用切片)
        test1(a[:])
    }
    
    
    //*[3]int 类型的指针
    func test(x *[3]int){
        //x传入的是指针
        //x[1]=100      // 支持指针自动操作,不会报错,内部自动处理
        (*x)[1]=100     // 先解引用,再改值
        fmt.Println(x)  //x是一个指向数组的指针,地址 : 打印出 &[3 100 5]
    }
    
    
    func test1(x []int){
        x[0] = 100
        fmt.Println(x)
    }
    

    6. go 不支持指针运算

        //var b =156
        //a := &b
        ////不允许指针运算
        //a++
    

    7. 指向指针的指针

        var b int=156
        var a *int=&b
    
        var c **int
        c = &a
        fmt.Println(c)
    
        var d ***int
        d = &c
        fmt.Println(d)
    

    8. 数组指针与指针数组

    • 数组指针: 指向数组的指针
    • 指针数组: 数组里面放指针
        //数组指针
        var a[3]int =[3]int{1,2,3}
        var b *[3]int = &a
        fmt.Println(b)
    
        //指针数组
        var x,y,z=12,13,14
        var b [3]*int = [3]*int{&x,&y,&z}
        fmt.Println(b)
    

    二. 结构体 type struct

    go语言中的结构体,类似于面向对象语言中的类

    • go中的面向对象: 继承,封装,多态
    • 一系列属性的集合

    1.结构体定义

    定义一个结构体

    type 结构体名字 struct {
        属性1 类型
        属性2 类型
        
        
    // 大小写表示公有与私有
    type Person struct {
        name string
        age int
        sex int
    }
    

    2.结构体的使用

    func main(){
        p :=Person{}    //相当于实例化得到有一个对象
        var p Person =Person{}    //结构体的类型就是 Person
        fmt.Println(p)
        fmt.Println(p.name)
    } 
    
    type Person struct {
        name string
        age int
        sex int
    }
    

    3. 结构体的零值

     	var p Person// 值类型,零值是属性的零值
        p.name="jack"
        fmt.Println(p)
    

    4. 定义并初始化(传入属性)

    var p Person=Person{}
    
       按位置传
    var p Person=Person{"jack",15,1}
        按关键字传(位置可以乱,有几个值就要传几个值)
    var p Person=Person{name:"jack",age:15,sex:2}
    
    fmt.Println(p)
    fmt.Println(p.name)
    

    5. 创建匿名结构体

    没有名字,也没有type关键字,定义在函数体内部
    只使用一次,把一堆属性放到一个变量中
    
        a := struct {
           name string
           age int
           sex int
        }{age:18}
        fmt.Println(a.age)
    

    6. 结构体的指针

        var p Person=Person{sex:1,age:12}
        var p1 *Person=&Person{sex:1,age:12}    //指针
        var p1 *Person  // 结构体空值是nil
        fmt.Println(p1)
    

    7. 匿名字段

    • 字段没有名字
    • 做变量提升,提升字段:面向对象中的继承
    	// 按位置
        var p Person2=Person2{"lqz",18}
        //按关键字
        var p Person2=Person2{int:18,string:"jack"}
        fmt.Println(p)
    
    
    
    //匿名字段
    type Person2 struct {
        string
        int
        sex int     // 匿名与有名可以套用
    }
    

    8.嵌套结构体(结构体中套结构体)

        // 按位置
        var p Person3=Person3{"jack",12,Hobby{1,"蓝蓝"}}
        //按关键字
        var p Person3=Person3{name:"abc",hobby:Hobby{}}
        fmt.Println(p)
        //把hobby的id设置2,name设置为篮球
        p.hobby.name="篮球"
        p.hobby.id = 2
        fmt.Println(p)
    
    
    
    //结构体嵌套
    type Hobby struct {
        id int
        name string
    }
    type Person3 struct {
        name string
        age int
        hobby Hobby
    }
    

    9.字段提升(只把不重复的字段提升)

        // 按位置
        var p Person4=Person4{"jack"}
        //按关键字(面向对象的继承)
        var p Person4=Person4{name:"jack",Hobby2:Hobby2{}}
    
    //Hobby中的字段被提升了(可以直接.)
        p.hobby_id=2
        p.hobby_name="chenglong"
        p.Hobby2.hobby_id=3
    
        // go中通过匿名字段和结构体嵌套实现面向对象的继承
    
    
    --------------------------------
    // 字段提升
    type Hobby2 struct {
        hobby_id int
        hobby_name string
    }
    type Person4 struct {
        name string
        sex int
        age int
        Hobby2
    }
    

    10. 导出结构体(大小写)和字段(大小写)

    
    

    11.结构体相等性

    • 结构体是值类型。
    • 如果它的每一个字段都是可比较的,则该结构体也是可比较的。
    • 如果两个结构体变量的对应字段相等,则这两个变量也是相等的
    • 如果结构体包含不可比较的字段,则结构体变量也不可比较。

    三. 方法 fnuc (t type)

    python: 什么是方法(绑定给对象,类,自动传值),什么是函数
    
    go: 方法是绑定给结构体的: 结构体只有属性 + 方法 = 类
    

    1. 方法的定义

    func 关键字和方法名之间 加入了一个特殊的接收器类型
    func (t type) 方法名(){}
    

    2. 使用方法

        p :=Person4{"jack",28,1}
        //自动传值
        p.printName()
        // 有了函数,为什么还要方法
        效果一样,但是调用方式,以及函数必须传值等
    
    
    //定义一个结构体
    type Person4 struct {
        name string
        age int
        sex int
    }
    //给结构体绑定方法
    func (p Person4)printName(){
        fmt.Println(p.name)
    }
    
    //普通函数
    func printName(p Person4)  {
    	fmt.Println(p.name)
    }
    
    

    3. 指针接收器与值接收器

    值接收器,不会修改原来的

    指针接收器才会修改原来的

        p:=Person4{"jack",18,1}
        p.changeName("engo")    //值接收器
        //(&p).changeName("engo")    //值接收器,也可以
        p.changeAge(1111)       // 指针接收器
        //(&p).changeAge(1111)       // 指针接收器,没有区别
        fmt.Println(p)
        // 不管是值类型接收器,还是指针类型接收器,都可以用值和指针来调用
    
    
    
    //3. 指针接收器与值接收器
    func (p Person4)changeName(name string) {
        p.name=name
        fmt.Println(p)
    }
    //指针类型接收器的修改年龄
    func (p *Person4)changeAge(age int) {
        //(*p).age=age    //解引用(正统的修改)
        p.age=age   // 可以直接修改
        fmt.Println(p)
    }
    

    4. 那么什么时候使用指针接收器,什么时候使用值接收器

    指针接收器也可以被使用在如下场景:当拷贝一个结构体的代价过于昂贵时
    

    5. 匿名字段的方法

        p :=Person5{}
        //匿名字段的方法也会提升
        p.hobbyName="篮球"
        p.printName()   // 继承.子类没有printName方法,就会调用父类的
        //指定调用父类的printName方法(面向对象的super())
        p.Hobby1.printName()
    
    
    
    
    //匿名字段的方法
    type Hobby1 struct {
        id int
        hobbyName string
    }
    
    type Person5 struct {
        name string
        age int
        sex int
        Hobby1
    }
    //Hobby1 的绑定方法
    func (h Hobby1)printName(){
        fmt.Println(h.hobbyName)
    }
    //Person5 的绑定方法
    func (p Person5)printName(){
        fmt.Println(p.name)
    }
    

    6. 在方法中使用值接收器 与 在函数中使用值参数

    • 方法: 指针和值都可以来调用
    • 函数 只能传值

    7. 在方法中使用指针接收器 与 在函数中指针参数

    • 方法: 指针和值都可以来调用
    • 函数 只能传递指针

    8.在非结构体上的方法

        //像给int类型绑定个add方法可以吗?
        //var i int =10
        //i.add()  // 不行
    
    // 但是可以给传统数据类型重命名,然后绑定方法
        var i Myint=10
        i.add()
        i.add()
        i.add()
        fmt.Println(i)
    
    
    type Myint int //把int类型重命名为Myint
    
    func (i *Myint)add(){
        (*i)=(*i)+1     // 指针类型 解引用
    }
    

    四. 接口 type 名字 interface

    interface(接口)是golang最重要的特性之一,Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。

    简单的说:

    • interface是方法的集合
    • interface是一种类型,并且是指针类型
    • interface的更重要的作用在于多态实现

    1. 定义

    定义一个对象的行为,一系列方法的集合
    
    规范了子类应该有哪些行为,类似abc模块
    django中: 父类写了一个发布方法,没有d代码.只有一个raise, 子类继承,但是没有重写该方法,一调用就报错
    
    
    
    type  接口名称 interface {
    method1 (参数列表) 返回值列表
    method2 (参数列表) 返回值列表
    ...
    }
    

    2. 简单使用

    • 接口的使用不仅仅针对结构体,自定义类型、变量等等都可以实现接口。
    • 如果一个接口没有任何方法,我们称为空接口,由于空接口没有方法,所以任何类型都实现了空接口。
    • 要实现一个接口,必须实现该接口里面的所有方法。
    package main
    
    import "fmt"
    
    //1.定义了一个鸭子接口(run speak方法)
    type DuckInterface interface {
        run()
        //run(a int)int     // 有参数,有返回值
        speak()
    }
    
    
    
    
    //写一个唐老鸭结构体,实现该接口
    type TDuck struct {
        name string
        age int
        wife string
    }
    //实现接口(只要结构体绑定了接口中的所有方法,就叫做结构体实现了该接口)
    func (t TDuck)run() {   //传参的话,接口也必须定义
        fmt.Println("我是唐老鸭",t.name,"我会走路")
    }
    func (t TDuck)speak() {
        fmt.Println("我是唐老鸭",t.name,"我会说话")
    }
    
    
    
    //写一个肉鸭结构体
    type RDuck struct {
        name string
        age int
    }
    func (t RDuck)run() {   //传参的话,接口也必须定义
        fmt.Println("我是肉鸭",t.name,"我会走路")
    }
    func (t RDuck)speak() {
        fmt.Println("我是肉鸭",t.name,"我会说话")
    }
    
    func main() {
        //实例化
        var t TDuck=TDuck{"嘤嘤怪",17,"刘亦菲"}
        var r RDuck=RDuck{"怪五",18}
        //唐老鸭的run
        t.run()
        //肉的run
        r.run()
    
        //定义一个鸭子接口类型(肉鸭和唐老鸭都实现了鸭子接口,所以都可以把对象赋值给鸭子接口)
        var i1 DuckInterface
        i1 = TDuck{"嘤嘤怪",17,"刘亦菲"}
        var i2 DuckInterface
        i2 = RDuck{"怪五",18}
        //分别实现run方法
        i1.run()
        i2.run()
    }
    
  • 相关阅读:
    立体匹配中宽基线与窄基线的定义
    基于MST的立体匹配及相关改进(A Non-Local Cost Aggregation Method for Stereo Matching)
    Object Removal by Exemplar-Based Inpainting 概括(附源码)
    使用matlab进行空间拟合
    C# 控件 DevExpress的DateEdit设置显示日期和时间
    C#获取当前程序运行路径的方法集合
    《Entity Framework 6 Recipes》中文翻译系列 (14) -----第三章 查询之查询中设置默认值和存储过程返回多结果集 (转)
    《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查询之使用Entity SQL
    《Entity Framework 6 Recipes》中文翻译系列 (12) -----第三章 查询之使用SQL语句 (转)
    《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询 (转)
  • 原文地址:https://www.cnblogs.com/fwzzz/p/12734552.html
Copyright © 2011-2022 走看看