• Go语言自定义类型


    Go语言与C/C++类似,C++可通过typedef关键字自定义数据类型(别名、定义结构体等),Go语言则通过type关键字可实现自定义类型的实现

    1、自定义类型格式

    用户自定义类型使用type,其语法格式为:

    type newType oldType

    oldType可以是自定义类型、预声明类型、未命名类型中的任意一种
    newType是新类型标识符,与oldType具有相同的底层类型,并且都继承了底层类型的操作集合(如底层类型是map,支持range迭代访问,则新类型也可以使用range迭代访问)。此外,newTypeoldType是两个完全不同的类型,newType不会继承oldType的方法。

    关于newType和oldType是两个完全不同的的类型?
    在Go中分为命名类型和未命名类型
    命名类型:通过标识符符来表示。Go 语言允许用户定义类型。当用户声明一个新类型时,这个声明就给编译器提供了一个框架,告知必要的内存大小和表示信息。声明后的类型与内置类型的运作方式类似。 Go 语言里声明用户定义的类型有两种方法。最常用的方法是使用关键字 struct,它可以让用户创建一个结构类型。
    未命名类型:一个类型由预声明类型、关键字和操作符组合而成。未命名类型又称为类型字面量(Type Literal)。Go 语言的基本类型中的复合类型:数组(array)、切片(slice)、字典(map)、通道(channel)、指针(pointer)、函数字面量(function)、结构(struct)和接口(interface)都属于类型字面量,也都是未命名类型。所以 *int、[]int、[2]int、map[k]v 都是未命名类型。注意:用 type 声明的结构和接口是命名类型。

    举例:

    type INT int //INT 是一个使用预声明类型声明的自定义类型
    type Map map[string]string //Map 是一个使用类型字面量声明的自定义类型
    type myMap Map //myMap 是一个自定义类型Map 声明的自定义类型
    // INT, Map 、myMap 都是命名类型
    

    2、自定义struct类型

    定义:

    type identifier struct {
    field type1
    field type2
    }

    2.1 初始化

    方式一:通过var声明结构体
    在 Go 语言中当一个变量被声明的时候,系统会自动初始化它的默认值,比如 int 被初始化为 0,指针为 nil。
    var 声明同样也会为结构体类型的数据分配内存,所以我们才能像上一段代码中那样,在声明了 var s T 之后就能直接给他的字段进行赋值
    方式二:使用new
    使用new函数给一个新的结构体变量分配内存,它返回指向已分配内存的指针:var t *T = new(T)

    type struct1 struct {
        i1 int
        f1 float32
        str string
    }
    
    func main() {
        ms := new(struct1)
        ms.i1 = 10
        ms.f1 = 15.5
        ms.str= "Chris"
    
        fmt.Printf("The int is: %d\n", ms.i1)
        fmt.Printf("The float is: %f\n", ms.f1)
        fmt.Printf("The string is: %s\n", ms.str)
        fmt.Println(ms)
    }
    

    与面向对象语言相同,使用点操作符可以给字段赋值:structname.fieldname = value
    同样的,使用点操作符可以获取结构体字段的值:structname.fieldname
    方式三:使用字面量

    type Person struct {
        name string
        age int
        address string
    }
    
    func main() {
        var p1 Person
        p1 = Person{"lisi", 30, "shanghai"}   //方式A
        p2 := Person{address:"beijing", age:25, name:"wangwu"} //方式B
        p3 := Person{address:"NewYork"} //方式C
    }
    

    在(方式A)中,值必须以字段在结构体定义时的顺序给出。(方式B)是在值前面加上了字段名和冒号,这种方式下值的顺序不必一致,并且某些字段还可以被忽略掉,就想(方式C)那样。
    除了上面这三种方式外,还有一种初始化结构体实体更简短和常用的方式,如下:

    ms := &Person{"name", 20, "bj"}
    ms2 := &Person{name:"zhangsan"}
    

    &Person{a, b, c}是一种简写,底层仍会调用new(),这里值的顺序必须按照字段顺序来写,同样它也可以使用在值前面加上字段名和冒号的写法(见上文的方式B,C)。

    表达式 new(Type) 和 &Type{} 是等价的。

    2.2、几种初始化方式之间的区别

    上述了解了Go语言中的三种初始化结构体的方式:

    //第一种,在Go语言中,可以直接以 var 的方式声明结构体即可完成实例化
    var t T
    t.a = 1
    t.b = 2
    
    //第二种,使用 new() 实例化
    t := new(T)
    
    //第三种,使用字面量初始化
    t := T{a, b}
    t := &T{} //等效于 new(T)
    

    使用var t T会给t分配内存,并零值化内存,但这个时候的t的类型是T
    使用new 关键字时,t := new(T),变量t则是一个指向T的指针
    从内存布局上来看,对三种初始化方式的区别:

    使用var声明:

    使用new初始化:

    使用结构体字面量初始化:

    举例:

    package main
    import "fmt"
    
    type Person struct {
     name string
     age int
    }
    
    func main() {
     var p1 Person
     p1.name = "zhangsan"
     p1.age = 18
     fmt.Printf("This is %s, %d years old\n", p1.name, p1.age)
    
     p2 := new(Person)
     p2.name = "lisi"
     p2.age = 20
     (*p2).age = 23 //这种写法也是合法的
     fmt.Printf("This is %s, %d years old\n", p2.name, p2.age)
    
     p3 := Person{"wangwu", 25}
     fmt.Printf("This is %s, %d years old\n", p3.name, p3.age)
    }
    

    输出:

    This is zhangsan, 18 years old
    This is lisi, 23 years old
    This is wangwu, 25 years old
    

    面例子的第二种情况,虽然 p2 是指针类型,但我们仍然可以像 p2.age = 23 这样赋值,不需要像 C++ 中那样使用 -> 操作符,Go 会自动进行转换。
    注意也可以先通过 * 操作符来获取指针所指向的内容,再进行赋值:(*p2).age = 23

    2.3 结构体的内存布局

    Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。不像 Java 中的引用类型,一个对象和它里面包含的对象可能会在不同的内存空间中,这点和 Go 语言中的指针很像。下面的例子清晰地说明了这些情况:

    type Rect1 struct {Min, Max Point }
    type Rect2 struct {Min, Max *Point }
    

    参考:[1] https://www.cnblogs.com/liyutian/p/10050320.html
    [2] https://blog.csdn.net/wohu1104/article/details/106202892

  • 相关阅读:
    准备用协程模拟经典的生产者消费者
    重载操作符号
    对象池
    ssh加key
    oracle存储过程(PL/SQL)
    获取服务器ip地址
    【STL系列】结构体排序
    strtol sort snprintf snscanf strtok
    cxGrid动态创建带CheckBox列时遇到的问题...
    Windows2003 安装PostgreSQL9.0 UUID解决‘ERROR:无法载入程式库’问题
  • 原文地址:https://www.cnblogs.com/whiteBear/p/15549604.html
Copyright © 2020-2023  润新知