• Go笔记-结构体


    结构体简介

      Go 通过类型别名(alias types)和结构体的形式支持用户自定义类型,或者叫定制类型。一个带属性的结构体试图表示一个现实世界中的实体。结构体是复合类型(composite types),当需要定义一个类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在一起。然后可以访问这些数据,就好像它是一个独立实体的一部分。结构体也是值类型,因此可以通过 new 函数来创建。

      组成结构体类型的那些数据称为 字段(fields)。每个字段都有一个类型和一个名字;在一个结构体中,字段名字必须是唯一的。

      Go中没有类的概念

    结构体定义

    • 如果字段在代码中从来不会用到,那么就可以把它命名为_(单独使用下划线,在Go中表示忽略)
    • 结构体的字段可以事任何类型,也可以是函数或是接口
     1 type identifier struct{
     2     field1 type1
     3     field2 type2
     4     ...
     5 }
     6  
     7 // 声明
     8 var s identifier
     9 identifier.field1 = value
    10 identifier.field2 = value

    结构体声明

    1 // 下面三种相同,t为结构体指针
    2 var t *T  // T是结构体类型
    3 t = new(T)  // 结构体指针变量t
    4  
    5 var t *T = new(T)
    6  
    7 t := new(T)  // 指针变量t
        不使用new的声明方式:var t T 也会给t分配内存,并零化内存,t为类型T而不是指针类型*T
     

    结构体赋值和使用

        使用点符号给字段赋值或者获取结构体字段的值,变量不管是结构体类型还是结构体指针类型,都使用点符号来引用结构体的字段
     注意当变量类型是指针结构体时,既可以通过指针给结构体字段赋值,也可以通过使用解指针的方式给结构体字段赋值,注意下面的例子
     1 import "fmt"
     2 type struct1 {
     3         i1 int
     4         f1 float32
     5         s1 string     
     6     } 
     7 func main(){
     8    ms := new(struct1) // ms是*struct1类型
     9    ms.i1 = 10          // 这是通过指针给结构体字段赋值,也可以通过解指针的方式给结构体赋值 这样子(*ms).i1 = 10
    10    ms.f1 = 1.2
    11    ms.s1 = "hello,word"
    12    fmt.Println(ms.i1)
    13     fmt.Println(ms.f1)
    14     fmt.Println(ms.s1)    
    15 }
     
     

    结构体初始化

     1 // 方式一
     2 ms:=&struct1{10,1.1,"gao"}  // ms的类型是*struct1
     3  
     4 // 方式二
     5 var ms struct1
     6 ms = struct1{10,1.1,"hu"}  // ms的类型是ms
     7 // 举例
     8 type Interval struct{
     9     start int
    10     end int
    11 }
    12 // 以下三种初始化方式
    13 intr := Interval{0,3}
    14 intr := Interval{start:3,end:3}
    15 intt := Interval{end:4}
     
     

    结构体的内存分布

    Go语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。
    1 type Rect1 struct {Min, Max Point}
    2 type Rect2 struct {Min, Max *Point} 
     结构体的内存布局
     

    【结构体转换】

    Go中的类型转换遵循严格的规则。当为结构体定义了一个alias类型时,此结构体类型和它的alias类型都有相同的底层类型。
    1 package main
    2  
    3 type number struct{
    4     a int
    5 }
    6  
    7 type aliasNumber number  // 为结构体number定义了一个alias类型 aliasNumber
     
     

    Go中实现构造方法

        1- 原本不存在构造方法
     1 type File struct {
     2     fd int // 文件描述符
     3     name string // 文件名
     4 }
     5  
     6 fun newFile(fd int, name,string)*File{
     7     if fd<0{
     8         return nil
     9     }
    10     return &File{fd,name}
    11 }
        2- 强制用户使用工厂方法:前面提到过,变量小写就会变成私有的,这里的实现也是这个原理。将结构体定义为私有的,在开放一个共有的方法来返回结构的指针。
     1 type matrix struct{
     2     //
     3 }
     4 func NewMatrix(params)*matrix{
     5     m := new(matrix)
     6     return m
     7 }
     8  
     9 // 在其他包中引入使用
    10 package main
    11 import "matrix"
    12 wrong := new(matrix.matrix)  // wrong way
    13 right := matrix.NewMatrix(...)  //  right way
     

    带标签的结构体

      结构体的字段除了有名字和类型外,还可以有一个可选的标签:它是附属于字段的字符串,可以是文档或其他的重要标记。标签的内容不可以在一般的编程中使用,只有反射包reflect能够获取它。

           示例如下

     1 package main
     2 
     3 import "fmt"
     4 import "reflect"
     5 
     6 type TagType struct{
     7   f1 bool "an important answer"
     8   f2 string "the name of the thing"
     9   f3 int  "how much there are"
    10 }
    11 
    12 fun main(){
    13   tt := TagType{true,"kobe",82}
    14   for i:=0;i<3,i++{
    15     refTag(tt,i)
    16   }
    17 }
    18 func refTag(tt TagType,ix int){
    19     ttType := reflect.Typeof(tt)
    20    ixField := ttType.Field(ix)
    21    fmt.Printf("%v
    ",ixField.Tag)
    22 }

    结构体中的匿名字段

      结构体中可以包含一个或多个匿名字段(字段没有名字,只有类型,这个类型可以包括结构体类型),但是一个结构体中只能包含一种类型的匿名字段。比如不能同时包含两个int int匿名字段(结构体类型也是同样的道理)。

      使用带有匿名字段的结构体时,类型名称就是字段名,这就是为什么一个类型只能出现一次了。

    package main
    import "fmt"
    type struct1 struct{
      f1 int
      f2 bool
      f3 string
      float32
      struct2
    }
    type struct2 struct{
      s1 string
    }
    func main(){
      s1 := new(struct1)
      s1.f1 = 1
      s1.f2 = true
      s1.f3 = "boom"
      s1.float32 = 2.3
      s1.s1 = "childern"
      fmt.Println(s1)
    }

    结构体中出现命名冲突

    • 外层名字会覆盖内层名字(但是两者的内存空间都保留),这提供了一种重载字段或方法的方式
    • 如果相同的名字在同一级别出现了两次,如果这个名字被程序使用了,将会引发错误。

      如果想要使用内层的就通过层层去调用

     1 package main
     2 
     3 import (
     4     "fmt"
     5 )
     6 
     7 type A struct {
     8     a int
     9 }
    10 type B struct {
    11     a int
    12     b int
    13 }
    14 
    15 type C struct {
    16     A
    17     B
    18 }
    19 
    20 
    21 func main() {
    22     var c_struct C
    23     c_struct.A.a = 10
    24     c_struct.b = 20
    25     c_struct.B.a  =30
    26 
    27     fmt.Println(c_struct)
    28 
    29 }
     
     
     
     
  • 相关阅读:
    树莓派的入网方式和远程连接
    数据结构与算法之递归(C++)
    c++中字符串输入注意的问题
    基于视觉的机械臂分拣(二)
    基于视觉的机械臂分拣(一)
    数据结构与算法之折半查找(C++)
    数据结构与算法之顺序查找(C++)
    ROS之USB摄像头识别二维码问题解决
    机械臂开发之正运动学
    利用vs pcl库将多个PCD文件合并成一张PCD地图
  • 原文地址:https://www.cnblogs.com/ymkfnuiwgij/p/7912191.html
Copyright © 2020-2023  润新知