首页 > 其他分享 >04-Go字符串、指针、结构体

04-Go字符串、指针、结构体

时间:2023-03-02 15:56:31浏览次数:40  
标签:04 Person int fmt var Println Go 指针

1 字符串

package main

// 字符串
func main() {
    var a string = "hello world"
    
    //1 按索引取值,只能取,不能改
    fmt.Println(a[0])    //104   utf-8 对照的十进制 数字
    
    
    //2 循环字符串  全英文    --->按字符/字节都一样,英文就只占一个字节
    for i, v := range a {
        fmt.Println(i, v, string(v))  //string() 强制类型转化
    }
    
    
    //3 迭代循环字符串  混着中文   --->按字符
    var a string = "hello world 中国"
    
    for i, v := range a {
        fmt.Println(i, v, string(v))
    }

    
    //4 索引循环字符串  混着中文   --->按字节
    for i := 0; i < len(a); i++ {
        fmt.Println(i, a[i], string(a[i]))   //中文部分会出现乱码
    }
    

    //5 字符串的长度  
        len:字节长度   
        utf8.RuneCountInString(s): 字符长度  //字符串中Rune的个数  Rune是int32 4个字节,所有字符最多4个字节
    
    fmt.Println(len(a))                     //18个字节
    fmt.Println(utf8.RuneCountInString(a))  //14个字符 

}

2 指针

//一、指针的含义
  指针就是地址,获取变量的指针就是 获取变量的地址(首字节地址)


//1 获取变量的指针:  &变量 
  var x int = 100

  fmt.Println(&x)  //0xc000016070

  x=200            //变量相当于一个容器,为变量填充一个新值,容器的地址不变
  fmt.Println(&x)  //0xc000016070



// 2 通过指针操作变量值:  *指针  表示对指针解引用,获取 指针指向的值
  fmt.Println(*(&x)) //200   

  //通过变量的指针修改值
  *(&x)=300
  fmt.Println(*(&x)) //300
  fmt.Println(x)     //300 



// 3 指针的类型:   *值类型    eg: 变量x的类型为int,那指针&x的类型为 *int
  变量的指针与变量名一样,都是指向首地址的 (首个字节单元的地址)
  故指针也必须有类型,才能在取到首地址后,根据类型的大小规定,取出变量值 后续的内容

  var x int = 100
  var y string = "hello"

  fmt.Printf("%T", &x)  //输出类型:*int
  fmt.Printf("%T", &y)  //输出类型:*string

//二、指针变量     常用这个,操作更清晰
  指针变量是 存储 变量内存地址 的变量  //将指针(地址)保存到一个变量中

  & 放在变量前,表示取出变量的指针(内存地址)

  * 放在类型前,表示该指针变量的类型,也就是该指针的类型  //指针变量 定义时使用
                 是在指针 指向的值 的类型 前加*

              是 指向这个类型(指向的值 的类型) 的 指针

    eg: 变量x的类型为int,那指针变量p(就是指针&x)的类型为 *int


  * 放在指针变量前,表示解引用,会反解出指针(地址)指向的值  //通过指针变量,获取另一个变量 指针的值



package main

import "fmt"


func main() {
    //指针变量:使用一个新变量 存 变量a 的内存地址,该新变量就是指向a的指针

    //1 取一个变量a的内存地址   借助'&'
    var a int=100
    var p *int= &a  //定义指针变量p
    
    //有了指针变量p,*p就是*(&x),即*(变量x的地址),操作将会更加清晰
    fmt.Println(p)   //p的值为变量x的地址:0xc000016070
    fmt.Println(*p)  //*p即*(&x),结果为:100
    fmt.Println(&p)  //指针变量p本身也肯定是有地址的:0xc00000e030

    
    //2 开启套娃
    var a =100
    var p *int=&a
    
    fmt.Println(a)   //变量a的值 : 10
    fmt.Println(p)   //指针变量p : 变量a的指针
    fmt.Println(*p)  //解引用,把p指向的真正值打印出来,a --> 10

    
    var p1 **int=&p
    //p1 :=&p
    
    fmt.Println(p1)  //指针变量p1 : 指针变量p的指针
    

    var p2 ***int=&p1
    //p2:=&p1
    
    fmt.Println(p2)     //指针变量p2 : 指针变量p1的指针
    fmt.Println(***p2)  //***p2 ---> **(*p2) ---> **p1 ---> *(*p1) ---> *p ---> 100

    

    //3 指针的零值    指针是引用类型 零值为nil    
    var p *int
    
    fmt.Println(p)  //<nil>

    
    //4 指针 当做函数参数传递时,会影响原来的值
    var a =100
    var p *int=&a
    
    test1(p)        //101
    fmt.Println(a)  //101

    
    //5 不要向函数传递数组的指针,而应该使用切片
        因为传递函数参数时,参数是数组的指针 的话
        若每次传递数组的长度不一定,函数中参数类型中 数组长度需要每次修改
    
    var a [3]int=[3]int{1,2,3}
    var b [5]int=[5]int{1,2,3}

    test2(&a)       //若换成b数组指针 &b,则函数test2 参数的类型也要修改
    fmt.Println(a)

    test3(a[:])     //参数为切片时,就比较统一,不用修改
    fmt.Println(a)
    
    
    //6 指针数组 和 数组指针
    
    //6.1 指针数组: 是数组,放指针的数组
    var a =10
    var b =11
    var c =12
    var p1 [3]*int=[3]*int{&a,&b,&c}
    
    fmt.Println(p1)      //[0xxx1  0xxx2  0xxxx3]
    fmt.Println(*p1[0])  //10


    //6.2 数组指针: 是指针变量,指向数组的指针
    var a [3]int=[3]int{1,2,3}
    var p2 *[3]int=&a
    
    fmt.Println(p2)  //&[1 2 3]  就是a数组的指针(地址)
}



func test1(p *int)  {
    *p+=1
    fmt.Println(*p)  //101
}


func test2(p *[3]int)  {
    (*p)[0]=999
    fmt.Println(*p)  
}


func test3(p []int)  {
    p[0]=999
    fmt.Println(p)
}

3 结构体

//含义
  是用户自定义的 类型,表示若干个字段的集合
  ---> python面向对象的类:属性和方法的集合
  ---> 结构体是python面向对象中类 概念的一半,只有属性,没有方法


//使用场景
  有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体




package main

import ("fmt")


//1 定义结构体
type Person struct {
    name string
    age uint8
    hobby string
}

//eg: 定义一个Hobby结构体
type Hobby struct {
     //hobbyName string
     //hobbyId int
     string   //匿名字段:字段没有名字,实则以类型作为字段名字
     int
}



func main() {
    
    //2 使用结构体 
    var p Person
    
    //定义并初始化
    var p Person=Person{"lqz",19,"篮球"}       //按位置初始化,有几个字段,就要传几个
    var p Person=Person{name: "lqz", age: 19}   //按关键字初始化,可以只传几个参数
    
    fmt.Println(p)  //{lqz 19 篮球}

    //3 使用结构体--赋值
    p.name="lqz"
    p.age=19
    p.hobby="篮球"
    
    fmt.Println(p.name)

    
    //4 匿名结构体  没有type和名字的结构体  
       ---> 只能定在函数内部使用,定义在外部,又没有名字,函数中咋使用尼
       ---> 把多个属性放到一个变量中,只使用一次
    
    var p1= struct{
        name string
        age int
    }{"egon",19}
    
    
    var p1= struct{
        name string
        age int
    }{age:19}
    
    fmt.Println(p1)


    //5 结构体的零值    值类型: 字段的零值
    var p Person=Person{"lqz",19,"篮球"}
    
    //值类型传递函数  原来结构体的值不会受影响
    test1(p)        //{刘亦菲 19 篮球}
    fmt.Println(p)  //{lqz 19 篮球}  

    //通过传递 结构体的指针,修改原来结构体的值
    test2(&p)       //&{刘亦菲 19 篮球}
    fmt.Println(p)  //{刘亦菲 19 篮球}

    
    
    //6 结构体 大小写字母开头的含义
        若在其他包,使用该结构体,注意结构体内的字段,也需要大写开头  
    
    //定义使用 package1包下 的 Person结构体
    //var p package1.Person=package1.Person{"lqz",19}
    var p =package1.Person{"lqz",19}  //推导模式,少些变量的类型
    
    var p package1.Person 
    
    fmt.Println(p.Name)
    fmt.Println(p)

    
    
    //7 结构体的指针
    //var p *Person = &Person{"lqz",19}
    var p = &Person{"lqz",19}   //p 为 Person结构体 的 指针变量
    
    p.Name="egon"   //结构体的指针,可以不解引用,直接使用到 结构体
    fmt.Println(p)  //&{egon 19}

    
    
    //8 匿名字段:  字段没有名字,以类型作为字段名  故类型不能重复
    
    h :=Hobby{"篮球",1}             //按位置传
    h :=Hobby{string:"篮球",int:1}  //按关键字传
    
    fmt.Println(h.string)   //篮球
    fmt.Println(h.int)      //1

    

    //9 结构体嵌套: 结构体中套结构体
    
    /*  应当定义在main函数外面
    type Person struct {
        name string
        age uint8
        hobby Hobby
    }

    type Hobby struct {
        hobbyName string
        hobbyId int
    }
    */
    
    p := Person{}
    p := Person{name:"lqz",age:19,hobby:Hobby{"篮球",1}}
    
    fmt.Println(p.hobby.hobbyName)  //篮球

    
    
    //10 结构体嵌套 + 匿名字段
    
    /*  应当定义在main函数外面
    type Person struct {
        name string
        age uint8
        hobby Hobby
    }

    type Hobby struct {   //1.Hobby结构体为匿名字段
        string
        int
    }
    */

    p := Person{name:"lqz",age:19,hobby:Hobby{"篮球",1}}
    fmt.Println(p.hobby.string)

    -----------------------------------------------------
    /*  应当定义在main函数外面
    type Person struct {   //2.Person结构体中 Hobby为匿名字段
        name string
        age uint8
        Hobby
    }

    type Hobby struct {   
        hobbyName string
        hobbyId int
    }
    */
    
    p := Person{name:"lqz",age:19,Hobby:Hobby{"篮球",1}}  //按关键字传
    p := Person{"lqz",19,Hobby{"足球",2}}                 //按位置传
    
    
    fmt.Println(p.Hobby.hobbyName)  //p.Hobby  类似于面向对象的super()
    fmt.Println(p.hobbyName)        //字段提升  提升到最外层
    
    //结构体嵌套 + 匿名字段: 实现了面对对象的继承
      当Hobby为匿名字段时,类似于继承 Person为子类,Hobby为父类
      p.hobbyName 类似于对象.属性  从自身类Person找不到,就去父类Hobby找
      p.Hobby     类似于面向对象的super()  指名道姓的 去父类中找


    
    //11 导出结构体和字段  根据大小写开头,决定是否在别的包内可以用
    

    //12 结构体相等性   
         -如果它的每一个字段都是可比较的,则该结构体也是可比较的
           若两个结构体变量的对应字段相等,则这两个变量也是相等的
    
         -如果结构体中有不可比较的字段,结构体就不能比较  //引用类型字段不可比较
    
    
    p1:=Person{name:"lqz",age:18}
    p2:=Person{name:"lqz",age:19}
    
    fmt.Println(p1==p2)  //true
}



func test1(p Person)  {
    p.name="刘亦菲"
    fmt.Println(p)
}


func test2(p *Person)  {
    //如果是结构体的指针,可以不用解引用,直接使用到 结构体
    p.name="刘亦菲"  // 等于 (*p).name="刘亦菲"
    fmt.Println(p)
}

标签:04,Person,int,fmt,var,Println,Go,指针
From: https://www.cnblogs.com/Edmondhui/p/17172066.html

相关文章

  • how golang build itself?
    howgolangbuilditself?https://www.reddit.com/r/golang/comments/vbibey/is_golang_compiler_open_source_from_noob/?sort=confidence"Thefirstgocompilerswer......
  • golang 生成Sqlserver数据表实体
    最近开始学习golang,公司原来很多项目都Sqlserver数据库的,世面上很多文章,都是关于Mysql的,自己参考了一个博主的文章,整了一个生成Sqlserver实体的小工具分享一下,能给个星......
  • C++ vs golang
    以前学过ruby,gml,lisp这些小众语言的我又开始了golang基本上所以语言,我觉得都应该和C++对比一下C++vsgolangInbrief,golangisalanguagewhichmixesC++,Pyth......
  • gopher必读文章
    GettingStartedwithGoProgramminghttps://www.programiz.com/golang/getting-startedHowtoWriteGoCodehttps://go.dev/doc/codeDocumentationhttps://pkg.go.dev/c......
  • go操作redis
    导学:如何学习?本人建议先安装redis,如何在命令敲一遍,最后再用go来实现效果更好。实战!实战!不实战就是凉凉!!!!!!!1.1什么是redis?redis:远程字典服务,是一种运行在内存上的非关系......
  • go解析IP
    //Copyright©2021sealos.////LicensedundertheApacheLicense,Version2.0(the"License");//youmaynotusethisfileexceptincompliancewiththeLice......
  • 使用C#和Selenium将鼠标指针(光标)移动到特定位置或元素
    使用C#和Selenium将鼠标指针(光标)移动到特定位置或元素 我使用Selenium和C#执行单击操作。我可以执行点击操作,但我不能将鼠标指针(光标)移动到特定坐标或特定元素上。Ac......
  • docker+go+gin部署
    一、准备工作1、先确保项目可以正常运行二、编写Dockerfile文件,生成镜像FROMgolang:1.18.1WORKDIR/go/src/appADD.//go/src/appRUNgoenv-wGO111MODULE=......
  • go build
    gohelpbuildgotoollink--helpgotoolcompile--help   gobuild-ldflags"-s-w"x.go (goinstall类似)-s去掉符号表,然后panic的时候stacktrace......
  • Google Chrome Version 110 All In One
    GoogleChromeVersion110AllInOneGoogleChromeVersion110.0.5481.177(OfficialBuild)(x86_64)chrome://whats-new/效率边浏览,边利用侧边栏整理和标记重点......