golang笔记——数据类型

25个关键字

  程序声明:import,package

  程序实体声明和定义:chan,const,func,interface,map,struct,type,var

  程序流程控制:go,select,break,case,continue,default,defer,else,fallthrough,for,goto,if,range,return

类型

  18个基本类型:bool,string,rune,byte,int,uint,int8,uint8,int16,uint16,int32,uint32,int64,uint64,float32,float64,complex64,complex128

  7个复合类型:array,function,slice,channel

  其中,切片、字典、通道类型都是引用类型

  类型的声明一般以 type 关键字开始,然后是自定义的标识符名称,然后是基本类型的名称或复合类型的定义。

  Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。

  最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。

  一个float32类型的浮点数可以提供大约6个十进制数的精度,而float64则可以提供约15个十进制数的精度;通常应该优先使用float64类型,因为float32类型的累计计算误差很容易扩散,并且float32能精确表示的正整数并不是很大

操作符

  列举一些特殊的操作符,注意下面的位操作符

&      位运算 AND
|      位运算 OR
^      位运算 XOR
&^     位清空 (AND NOT)
<<     左移
>>     右移

  可以通过 Printf 函数的 %b 参数来输出二进制格式的数字。

特殊的空标识符

  下划线 _ 作为一个特殊的标识符,可以用于 import 语句中,仅执行导入包中的 init 方法。也可以作为赋值语句的左边,表示该变量并不关心且不使用。

  此外,标识符首字母的大小写,在GO语言中被用来控制变量或函数的访问权限,类似于其它语言的 public\private。

类型断言

  比较特殊的表达式有类型断言,如果判断一个表达式 element的类型是 T 的话,表达式为 element.(T),意思是 element不为 nil 且存储在其中的值是T类型。这里有两种情况,如果 T 不是一个接口类型,则 element必须要为接口类型的值,比如判断 100 是 int 型,不能使用 100.(int),而要用 interface{}(100).(int) ; 如果T 是一个接口类型,表示断言 element实现了 T 这个接口。如果函数的参数是一个空接口,则必须断言传入的接口实现类型,才能使用其对应的方法。

可变参函数

  最后一个参数为 ...T 的形式的函数即为可变参函数,意味着可变参数都是 T 类型(或实现了T的类型)如:func CallFunction(first string,t ...string),GO语言会在调用可变参函数时,创建一个切片,然后将这些可变参数放入切片中,但如果传入的可变参部分就是一个元素类型为T的切片的话,则直接把传入切片赋值给创建的切片,且在调用写法上也有区别,为: CallFunction("hello",[]string{"x","y"}...)

数组类型

  array: 声明一个长度为 n 、元素类型为 T 的数组为: [n]T,元素类型可以为基本类型也可以为复合类型,也可以不指定 n ,由推导得出,如: [...]string{"a","b"},数组长度 n = len([...]string{"a","b"}),另外如果指定了数组长度,但定义的数组长度小于声明的长度,则以声明长度为准,不足的元素补默认值。同一元素类型,但数组长度不同,则视为不同类型。

切片类型

  slice: 切片类型的声明为 []T数组,切片类型里没有关于长度的规定,其它跟数组一样,切片类型的零值是 nil。切片总是对应于一个数组,其对应的数组称为底级数组。切片和其底层数组的关系是引用关系,如果有修改都会影响到对方。

  切片的数据结构包含了指向其底层数组的指针、切片长度和切片容量。切片的长度很容易理解,切片的容量是什么呢,它是切片第一个元素到底层数组最后一个元素的长度。

字典类型

  map: 定义一个哈希表的格式为 map[K]V,其中 K 表示键的类型,V表示值的类型,如: map[string]bool{"IsOK":true,"IsError":false}

接口类型

  定义了一组方法声明,接口中可以包含接口

  GO语言对接口类型的实现是非侵入式的(备注:侵入式是指用户代码与框架代码有依赖,而非侵入式则没有依赖,或者说耦合),只要一个类型定义了某个接口中声明的所有方法,就认为它实现了该接口。

  一个特殊的接口: interface{} 是一个空接口,不包含任何方法声明,所以GO语言所有的类型都可以看成是它的实现类型,我们就可以使用它实现类似其它语言中的公共基类的功能。比如声明一个字典,键是字符串,值是不确定类型,就可以使用 map[string]interface{}

  判断一个类型是否实现了一个接口,可以通过类型断言来确定: _,ok := interface{}(MyType{}).(MyInterface)

函数与方法

  GO语言中,函数跟方法是有区别的,函数就是我们通常理解的函数,而方法是附属于某个自定义数据类型的函数,即存在某个接收者。

  func (self MyType) Len() int {} 这里的 (self MyInterface) 是表示方法接收者。

  值方法和指针方法,值方法是指接收者是一个对象,而指针方法是指接收者是一个对象指针。两者的区别是,值方法中对接收者的改变是副本级别的,而指针方法中对接收者的改变是地址级别的。所以其实一般都推荐使用指针方法,因为大多数情况下我们在方法内部修改接收者,都是为了真实的改变它,而不是改变一个副本。但是,对于引用类型的接收者来说,两者并无区别。

  匿名函数由函数字面量表示,函数是作为值存在的,可以赋给函数类型的变量。如:

    var myfunc func(int,int) int
    myfunc = func(x,y int) (result int) {
        result = x + y
        return
    }
    log.Println(myfunc(3,4))

  一个方法的类型是一个函数类型,即把接收者放到函数的第一个参数位置即可。

  非常遗憾,GO语言不支持函数和方法重载。

结构体

  可以包含字段,也可以包含匿名字段,一般匿名字段是接口类型,这样就相当于该结构体包含了该接口中的方法,另外也可以在结构里重写隐藏接口中的方法。

  

指针

  有一个专门用于存储内存地址的类型 unitptr,它与 int/unit 一样属于数值类型,存储32/64位无符号整数。

  可以在一个类型前面使用*号,来表示对应的指针类型,也可以在可寻址的变量前面使用&,来获取其地址。

常量

  定义常量和多个常量如下:

    const PP = iota        //0
    const QQ = iota          0

    const (
        A = 1
        B = 2
        C
        D = iota
        E
        F 
    )
    log.Print(A,B,C,D,E,F)
输出是: 1 2 2 3 4 5

  注意,iota 只能在 const 里使用,它是 const 的行数索引器,其值是所在const组中的索引值,单常量定义时 iota 就等于 0。另外,const组中某一项如果不赋值,则默认和上一个值一样,但如果前面是 iota ,则为上一个值+1。使用 iota 可以实现其它语言中的枚举。

变量

  变量的声明语句以 var 开始,声明多个变量时,和声明多个const的方法相同。

var x string = "df"
var x = "
x := "        此为简写形式。

数据初始化

  GO语言的数据初始化有两种方法,一是使用 new ,一是使用 make ,其中 new 是为某个类型分配内存,并设置零值后返回地址,如 new(T) 返回的就是指向T类型值指针值,即*T。如 new([3]int) 其实相当于 [3]int{0,0},所以它是一种很干净的内存分配策略。

  make 只用于创建切片类型、字典类型和通道类型(注意这三个类型的特点,都是引用类型),它对这些类型创建之后,还会进行必要的初始化,与 new 不同,它返回的就是指T类型的值,而不是指针值。

定义常量的方式是使用 const ,如 const PI = 3.14,如果定义多个常量可以使用

编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,但可能令人惊讶的是,这个选择并不是由用var还是new声明变量的方式决定的。 如果一个函数里声明一个局部变量,但是将其指针赋给一个全局变量,那么则不能将此局部变量放在栈中,而只能放在堆中,我们可以称之为该局部变量逃逸了,所以关于变量是分配在栈上还是堆上,是由编译器根据情况来选择的。

内建函数

  close 只接受通道类型的值

  len函数,可以应用于字符串、切片、数组、字典、通道类型

  cap函数,可以应用于切片、数组、通道类型

  new函数和make函数

  append函数和copy函数,应用于切片

  delete函数,根据字典的键删除某一项

  complex\real\imag函数,复数相关

  panic 函数,异常相关,它的参数一般是某个error接口的某个实现类型;recover 函数,不接受任何参数,返回 interface{} 类型,也就是意味着,它可以返回任意类型。recover返回的内容是与panic相关的,就是panic的参数内容。

  print\println 函数,这两个函数支持基本类型参数,且是可变参数。但输出格式是固定的,且GO语言不保证以后会保留这两个函数,所以知道就好,不推荐使用。可以使用 fmt.Print 和 fmt.Println 来代替,效果更佳。

合并书写:

和 var/const 类似,多个 type 定义可合并成组,如下:

type (
    Person struct {
        Name string
        Age  int32
    }   

    myfunc func(string) bool
)

尤其是在函数内部定义一堆临时类型时,可集中书写,可读性更好。

自增/自减运算符不同于其它语言,不能用作表达式,只能当独立的语句使用,且不能前置,只有后置形式,以尽可能避免该运算符带的复杂性问题。

unsafe.Pointer 与 uintptr 的区别:

前者类似 C 语言中的 void* 万能指针,能安全持有对象,但后者不行,后者只是一种特殊整型,并不引用目标对象,无法阻止垃圾回收器回收对象内存。

相关文章

类型转换 1、int转string 2、string转int 3、string转float ...
package main import s &quot;strings&quot; import...
类使用:实现一个people中有一个sayhi的方法调用功能,代码如...
html代码: beego代码:
1、读取文件信息: 2、读取文件夹下的所有文件: 3、写入文件...
配置环境:Windows7+推荐IDE:LiteIDEGO下载地址:http:...