zoukankan      html  css  js  c++  java
  • go语言学习(基本数据类型)

    值类型:

    int/uint :根据系统确定是32还是64位。此外还有int8/uint8、int16/uint16、int32/uint32、int64/uint64

    byte:字节型,相当于uint8。

    float:go语言中没有double型,因为已经有了float32/float64,分别精确到小数点后面7、15位。

    uintptr:保存32bit或64bit指针,应该是保存指针的地址

    数组array:

    数组是有类型的,比如var a [10]int= [10]int{1},a的类型为[10]int。

    数组之间可以比较相等==或者不相等(!=),前提是类型相同。如果数组间类型相同且内容依次都一致,那么两个数组相等;如果两个数组类型相同,内容不一致,那么数组不相等。

    数组间赋值是值拷贝,会拷贝整个数组的所有元素给另一个数组,而不是引用拷贝,这点和C很不一样!!!

    string

    有地方说string是不可变的。这里要从string的内部结构说起:

    1 type StringHeader struct {     
    2     Data uintptr     
    3     Len  int
    4 }

     string内部是一个指向某块内存的指针,加上内存块的长度。这里说的string不可变指的是uintptr指向的内存块的内容不可变,但是其指向可以变,用C语言描述一下就是:

    const T *uintptr;

    struct

    struct是值类型。struct的声明和初始化如下:

     1     type Person struct {
     2         Name string
     3         Age  int
     4     }//struct声明
     5 
     6     a := Person{
     7         Age:  1,
     8         Name: "hao",
     9     }//直接初始化赋值,每个赋值语句后面要有逗号
    10 
    11     b := Person{}    //空结构体
    View Code

    go语言中没有继承的概念,只有组合的概念,下面是个小例子:

     1 type Person struct {
     2     Name string
     3     Age  int
     4 }
     5 
     6 type teacher struct {
     7     Person
     8     field string
     9 }
    10 
    11 type student struct {
    12     Person
    13     score int
    14 }
    15 
    16 func main() {
    17     a := student{
    18         score:  100,
    19         Person: Person{"guhao", 18},
    20     }
    21     fmt.Println(a)
    22 }

    struct中的method

    go没有class,只有struct。但是struct中提供了method方法,但不支持重载。写法与函数类似,这样一个struct就和method绑定了起来。method可以访问struct的所有字段,事实上go语言struct字段的可见性是针对真个package而言的。

     1 type A struct {
     2     Name string
     3 }
     4 
     5 type B struct {
     6     Name string
     7 }
     8 
     9 func main() {
    10     a := A{
    11         Name: "gu",
    12     }
    13     a.Print("hao")
    14 }
    15 
    16 func (a A) Print(arg string) { //(a A)表示接收者,arg代表方法的参数
    17     fmt.Println(a.Name, arg)
    18 }

     基础类型起别名

     go语言中可以给基础类型起别名,类似于C语言一样。下面的例子是给int起了个别名TZ,然后给这个别名绑定了print方法:

     1 type TZ int
     2 
     3 func (a *TZ) print() {
     4     fmt.Println("TZ:", *a)
     5 }
     6 func main() {
     7     var a TZ = 100
     8     a.print()
     9 
    10     var b int
    11     b = a    //错误
    12     b.print()  //错误
    13 }

    虽然TZ是int的别名,但两者不能直接赋值,需要显式的类型强制转换。go语言将这两者视为不同的类型。

    1 var b int = 99
    2 a = TZ(b)
    3 a.print()

    引用类型:

    引用类型有三种:slicemap和channel

    slice

    slice其实是一个结构体,其中包含了指向底层数组的指针、长度、容量。所以改变slice的值也会改变对应的指向的底层数组。

    slice不支持==,或者!=

    map

    map内部实现是hashtable, 定义如下m:=make(map[int]string),每一级map需要单独初始化,否则直接用对二级map赋值会报错,而且是运行时候的错误,编译时无法发现。

    1 func main() {
    2     m := make(map[int]map[int]string)
    3     a, ok := m[2][1]
    4     if !ok {
    5         m[2] = make(map[int]string)
    6     }
    7     a = "A"
    8     fmt.Println(a, ok)
    9 }

    此外,map是引用类型,需要用make定义。而且map自动扩容,我需要学习。map的key必须支持==和!=操作(废话,不然怎么做通过key去查找)。

    channel

    接口类型

    interface

    函数类型

    func:函数也是一种类型,因为go语言的函数可以赋值给变量。不支持嵌套,重载和默认参数。支持closure。

     1 func closure(x int) func(int) int {
     2     fmt.Printf("%p
    ", &x)
     3     return func(y int) int {
     4         fmt.Printf("%p
    ", &x)
     5         return x + y
     6     }
     7 }
     8 
     9 func main() {
    10     x := 1
    11     fc := closure(x)
    12     fc(100)
    13     fc(200)
    14 }

    我打印了三次调用的x的地址,打印的结果显示三次调用用到的x的值都是一样的,所以闭包对的x不是值拷贝,而是引用(应该是为了节约空间)。

    defer语句

    go语言特有的,执行顺序和定义顺序相反,先定义的语句后执行。

    此外还支持panic和recover

     panic和recover

     1 func A() {
     2     fmt.Println("A")
     3 }
     4 
     5 func B() {
     6     defer func() {
     7         if err := recover(); err != nil {
     8             fmt.Println("recover in B")
     9         }
    10     }()
    11     panic("Panic in B")
    12 }
    13 
    14 func C() {
    15     fmt.Println("C")
    16 }
    17 
    18 func main() {
    19     A()
    20     B()
    21     C()
    22 }

    panic会导致程序中断,执行完了panic之后就不执行其他语句了,除非我们在panic执行前先注册了defer语句。因此recover登场了。recover必须和defer一起使用。可以帮助程序恢复执行。以上代码执行结构如下:

    类型转换只能显式转换,不能隐式转换

    1 var a int = 3
    2 var f float32 = float32(a)

     枚举类型

    枚举类型必须定义在const块内.

    1、const块内默认下一条使用上一条语句

    2、枚举值与iota出现的次数无关,与出现的位置有关:iota出现的位置代表了其值,默认从0开始。

     1 const (
     2     a = 'A'
     3     b
     4     c
     5     d = iota
     6     e = 'B'
     7     f = iota
     8     g
     9 )
    10 
    11 func main() {
    12     fmt.Println(a) //输出65
    13     fmt.Println(b) //输出65
    14     fmt.Println(c) //输出65
    15     fmt.Println(d) //输出3
    16     fmt.Println(e) //输出66
    17     fmt.Println(f) //输出5
    18     fmt.Println(g) //输出6
    19 }

     运算符

    有算术运算符和逻辑运算符、位运算符,写法和C语言一致。

    多了一个专门为channel准备的运算符<-

    A

    recover in B

    C

    new和make

    new返回的是指针,不会初始化变量,只是把新申请的空间内容值为零。用C语言写类似下面:

    1 T *obj=(T*)malloc(sizeof(T));
    2 memset(obj, 0, sizeof(T));

    但并不是很准确,因为go语言中不同变量类型的零值不一样,比如bool的零值为false,int为零值为0,string的零值为空串,指针的零值是nil。所以下面这段代码p==nil

    var p *[]int = new([]int) 

    内建函数make(T, args)与new(T)的用途不一样。它只用来创建slice,map和channel,并且返回一个初始化的(而不是置零),类型为T的值(而不是*T)。之所以有所不同,是因为这三个类型的背后引用了使用前必须初始化的数据结构。例如,slice是一个三元描述符,包含一个指向数据(在数组中)的指针,长度,以及容量,在这些项被初始化之前,slice都是nil的。对于slice,map和channel,make初始化这些内部数据结构,并准备好可用的值。

    内存管理

    特别值得注意的是,局部变量不是所有的都分配在stack中(new出来的对象当然在heap上),如果一个函数的局部变量返回后依然被使用,那么这个变量分配在heap上,而不是stack上。

  • 相关阅读:
    apache设置无缓存
    唤醒键盘时取消对特定类的position:fixed定位
    vscode增加sftp扩展
    浮层蒙版加载中实现方式
    管理应用程序版本Elastic Beanstalk
    向 Elastic Beanstalk 环境中添加数据库
    在 Amazon ECS 上运行 X-Ray 守护程序
    SNS Message Attributes
    ProvisionedThroughputExceededException
    使用 Amazon CloudWatch Events 检测和响应管道状态更改
  • 原文地址:https://www.cnblogs.com/howo/p/9033807.html
Copyright © 2011-2022 走看看