Go 类型与变量

类型

可以包含数据的变量(或常量),可以使用不同的数据类型或类型来保存数据。使用 var 声明的变量的值会自动初始化为该类型的零值。类型定义了某个变量的值的集合与可对其进行操作的集合。

基本类型

类型可以是基本类型,如:int、float、bool、string;

  • 布尔型 bool

    • 长度:1字节
    • 取值范围:[true,false]
    • 注意事项:不可以用数字代表true或false
  • 整型:int/uint

    • 根据运行平台可能为32位或64位
  • 8位整型:int8/unit8

    • 长度:1字节
    • 取值范围:-128~127 / 0~255
  • 16位整型:int16/unit16

    • 长度:2字节
    • 取值范围: $ [ -2^{16}/2 \longrightarrow 2^{16}/2 - 1 ] $ / $ [ 0 \longrightarrow 2^{16}-1 ]$
  • 32位整型:int32(rune别名)/unit32

    • 长度:4字节
    • 取值范围: $ [ -2^{32}/2 \longrightarrow 2^{32}/2 - 1 ] $ / $ [ 0 \longrightarrow 2^{32}-1 ]$
  • 64位整型:int64/unit64

    • 长度:8字节
    • 取值范围: $ [ -2^{64}/2 \longrightarrow 2^{64}/2 - 1 ] $ / $ [ 0 \longrightarrow 2^{64}-1 ]$
  • 浮点型:float32/float64

    • 长度:4/8字节
    • 小数点:精确到7/15位小数点
  • 字节型: byte(unit8别名

  • 复数: complex64/complex128

    • 长度:8/16字节
  • 足够保存指针的32位或64位整数型:uintptr

  • 其他值类型:

    • array
    • struct
    • string
  • 引用类型

    • slice
    • map
    • chan
  • 接口类型

    • interface
  • 函数类型

    • func

关于取值范围

有符号的需要区分正数,负数和零。基本是2的n次方,之后除于2,在取出0。

像:8位整型有符号是 - 2^8/2 ~ 2^8/2-1 就是 -128~127 / 0~255

无符号则是从0开始,最后再减一。

类型零值

零值并不等于空值,而是当变量被声明为某种类型后的默认值,通常情况下值类型的默认值为0,boolfalsestring为空字符串。结构化的类型没有真正的值,它使用 nil 作为默认值(在 Objective-C 中是 nil,在 Java 中是 null,在 C 和 C++ 中是NULL或 0)。值得注意的是,Go 语言中不存在类型继承。

1
2
3
4
5
6
7
func main() {
var a [5]int
fm.Println(a)
}

# export
[0 0 0 0 0]

类型别名

1
2
3
4
5
6
7
8
type (
byte uint8
rune int32
str string
)

var param str
param = "hello"

变量

单个变量的声明与赋值

  • 变量的声明格式: var <变量名称> <变量类型>
  • 变量的赋值格式:<变量名称> = <表达式>
  • 声明的同时赋值: var <变量名称>[变量类型] = <表达式>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var 变量名 [类型] [=] [初始值] 

// 变量的声明与赋值
var a int
a = 123

// 同时赋值
var b int = 2
// 类型由系统推断
var c = 321

// 最简写法
d := 233


fm.Println(a,b,c,d)

类型推导

如果在公开的自定义类型(结构)中,组合了只对自己可见的类型,且此类型的属性是公开的。其他地方在获取这个私有的类型时,只能通过:=去获取,因为无法直接使用这个类型,所以只能通过:=进行类型自动推断。

如何用一行代码交换整数 i 和 j 的值

1
i,j=j,i;

多个变量的声明与赋值

  • 全局变量的声明可以使用var()方式进行简写
  • 全局变量的声明不可以省略var,但可使用并行方式
  • 所有变量都可以使用类型推断
  • 局部变量不可以使用var()的方式简写,只能使用并行方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var (
// 使用常规方法
str1 = "hello "
// 使用并行方法以及类型推断
str2, str3 = "Go's", "World"
// str4 := 3 不可以省略 var
)

fm.Println(str1 + str2 + str3)


// 多个变量的声明
var a, b, c, d int
// 多个变量的赋值
a, b, c, d = 1, 2, 3, 4

// 多个变量声明的同时赋值
var e, f, g, h int = 5, 6, 7, 8
// 省略变量类型,由系统推断
var i, j, k, l = 9, 10, 11, 12
// 多个变量声明与赋值的最简写法
i, m, n, o := 13, 14, 15, 16

fm.Println(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)

// 赋值时忽略了第二个数,主要应用于函数的返回值中
a, _, c, d := 1, 2, 3, 4
fm.Println(a,c, d)

简写申明多个变量,一般称这种形式为 组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 常量的定义 - 常量组
const (
PI = 3.14
const1 = "1"
const2 = 2
const3 = "3"
)

// 全局变量的声明与赋值 - 全局变量组
// 在函数体内不支持这种简写
var (
integerNum = 1
integerNum2 = 1
)

// 一般类型声明
type (
newType int
type1 float32
type2 string
type3 byte
)

变量的类型转换

Go 是类型安全的

  • 不存在隐士转换,所有类型转换必须显式声明

  • 转换只能发生在两种互相兼容的类型之间

  • 类型转换的格式

    • 1
      <ValueA> [:] = <TypeOfValueA>(<ValueB>)

例子:

1
2
3
4
var a float32 = 1.1
b := int(a)

fmt.Println(a,b)

以下这段中,b最后的输出是A,而不是字符串65string()表示将数据转换成文本格式,因为计算机中存储的任何东西本质上都是数字,因此此函数自然地认为我们需要将数字65表示为文本A

1
2
3
4
5
func main() {
var a int = 65
b := string(a)
fmt.Println(a,b)
}

那么如何将数字65转成字符串65? 需要导入新的包strconv帮助进行转换。

1
2
3
4
5
6
7
8
9
10
import (
"fmt"
"strconv"
)

func main() {
var a int = 65
b := strconv.Itoa(a)
fmt.Println(a, b)
}
  • strconv.Itoa:将数字转成字符串
  • strconv.Atoi:将字符串转成数字

指针

Go不支持指针运算,也有垃圾回收机制。

1
2
3
4
5
6
func TestHello(t *testing.T) {
a := 1;
aPtr := &a;
t.Log(a, aPtr);
t.Logf("%T %T", a, aPtr);
}

结果:

1
2
1 0xc00000c2c8
int *int

试一下指针运算:

1
2
3
4
5
6
7
func TestHello(t *testing.T) {
a := 1;
aPtr := &a;
t.Log(a, aPtr);
+ aPtr = aPtr + 1 ;
t.Logf("%T %T", a, aPtr);
}

结果:

1
invalid operation: aPtr + 1 (mismatched types *int and int)
- the End -
0%