乐趣区

Golang-基础数据类型一

基础数据类型

在 Go 语言中,数据类型用于声明函数与变量、常量数据的类型,声明何种数据类型主要是为了提高内存的利用率,因为不同的数据类型在内存所需要的空间大小是不一样的。

Golang 内置基础数据类型如下表所示:

数据类型名称 类型和描述
boolean 布尔型,值可以是常量 true 或 false
int&uint 带符号和无符号两种整型。int8,int16,int32(rune),int64 和 uint8(byte),uint16,uint32,uint64。uintptr 类型在指针小节中单独介绍。
float32&float64 Golang 没有 float 这种类型,只有 float32 和 float64 两种类型
complex64&complex128 复数类型,complex64 包含 float32 实部和虚部,complex128 包含 float64 实部和虚部
string 字符串类型,默认使用 UTF- 8 编码,且字符串的值是固定的,不可变化
派生类型 切片类型(slice)、字典(map)、通道类型(channel)、指针类型(pointer)、数组类型(array)、结构化类型(struct)、函数类型(function)、接口类型(interface)、错误类型(error)

整型

Golang 一共有 9 种不同大小的整型,无符号和带符号分别各占四种,还有一种 uintptr 类型,多用于底层编程。

Golang 除了支持常规整型运算(四则运算),还支持比较运算。

var x int16
var y int32

func main() {
    x, y := 2, 4
    if x == y {fmt.Println("x 等于 y(错误)") // 编译不通过,因为不同类型不能相互比较
    }

    if x == 2 || y == 2 {fmt.Println("x 等于 y(正确)") // 可用字面量比较
    }
}

位运算

(施工中)

浮点型

在 Go 语言中没有 float 这种类型,只有 float32 和 float64 两种类型,float32 精确到小数点后七位,float64 精确到小数点后十五位。由于精度不同的原因,在使用 ”==” 和 ”!=” 来比较浮点数时需要特别注意,事先测试运算可以避免不少的问题。

由于标准库 math 包中所有关于数学运算的函数都要求接收 float64 这个类型,所以在日常编写 Go 语言程序时,尽量使用 float64 类型。

复数类型

Go 语言的复数类型有两个:complex64 和 complex128,分别由两个 float32 和 float64 实部和虚部组成。

func main() {

    var v1 complex64 // 由两个 float32 构成的复数类型
    v1 = 1.2 + 11i

    v2 := 1.2 + 11i // 隐式声明,默认是 complex128 类型,分为 float64
    v3 := complex(1.2, 11)

    //h := v1 + v2 //float64 与 float32 类型不匹配,因此不能编译通过
    v := v2 + v3 //v3 数值等于 v2
    fmt.Println(v1, v2, v3, v)

    vr := real(v) // 获取实部的值
    vt := imag(v) // 获取虚部的值
    fmt.Println(vr, vt)
}

cmath 包中包含了一些关于操作复数的方法,除非是对内存有严格限制的程序,否则 建议使用 complex128 作为声明类型,减少后续类型转换的操作。

字符串

Go 语言默认支持 UTF- 8 编码,一个字符串是一个不可改变的 UTF- 8 字符序列,一个 ASCII 码占用 1 字节,其他字符根据需要占用 2~4 字节。这样的设计带来的好处有两个:一个是可以减少内存空间的使用,节约硬盘空间,第二个是统一编码格式有助于减少编码和解码的工作,提高编译效率。

Go 语言字符串类型支持以下两种形式的字面值

  • 解释字符串

该类字符串使用一对双引号 ”” 括起来,在这当中相关的转义字符将被替换,不支持换行,会解析转义字符

  • 非解释字符串

该类字符串使用一对反引号 ` 括起来,支持换行,引号内所有的内容(包括转义字符)全部输出

func main() {
  /* 打印输出
  * 我家住在隔壁的 \n  
  *    钓鱼城大学
  * 我家住在隔壁的
  * 钓鱼城大学
  */
    str1 := ` 我家住在隔壁的 \n  
    钓鱼城大学 `
    str2 := "我家住在隔壁的 \n 钓鱼城大学"
    fmt.Println(str1) // 完全输出反单引号括号内的内容并且可以跨行,不解析转义字符
    fmt.Println(str2) // 双引号内的不能换行,并且会解析转义字符

}
  • 操作字符串

虽然字符串是不能改动的,但可以通过索引逐个读取它的值。

func main() {
    s := "abcd 你" // 一个汉字占 3 字节,一共 7 字节长度
    for i := 0; i < len(s); i++ {fmt.Println(s[i])
    }
    /*
        *c := s[len(s)] // 访问超出字符串索引范围的字节会输出 panic 异常,编译不报错,执行会报错
        fmt.Println(len(s), c)
    */
    fmt.Println(s[0:4]) // 打印从第 0 字节到第 4 字节的字符串,abcd
    fmt.Println(s[:])   // 打印全部字节的字符串,abcd 你
    fmt.Println(s[2:])  // 打印从第 2 字节之后的字符串,cd 你
    fmt.Println(s[:3])  // 打印从第 0 字节到第 3 字节(不包括最后字节的字符串),abc
    fmt.Println(s[1:2]) // 打印从第 1 字节到第 2 字节的字符串(不包括最后字节的字符串),b
}

由于像汉字这种非 ASCII 字符的 UTF- 8 编码由多个字节构成,一个汉字占 3 字节长度;所以,第 i 个字节并不一定是字符串的第 i 个字符。例如,打印从第 0 字节到第 6 字节的字符串长度,由于汉字 “ 你 ” 占 3 个字节长度,选取索引值为 6 的字符串返回的是一个 “�”,并非完整的汉字字符串。

$ fmt.Println(s[0:6])
$ abcd�
  • 连接字符串

除了截取字符串,还可以使用 + 符号连接字符串。

func main() {
    s := "abcd 你" // 一个汉字占 3 字节,一共 7 字节长度
    for i := 0; i < len(s); i++ {fmt.Println(s[i])
    }
    /*
    *c := s[len(s)] // 访问超出字符串索引范围的字节会抛出 panic 异常
    *fmt.Println(len(s), c)
    */
    fmt.Println(s[0:4]) // 打印从第 0 字节到第 4 字节的字符串,abcd
    fmt.Println(s[:])   // 打印全部字节的字符串,abcd 你
    fmt.Println(s[2:])  // 打印从第 2 字节之后的字符串,cd 你
    fmt.Println(s[:3])  // 打印从第 0 字节到第 3 字节,abc
    fmt.Println(s[1:2]) // 打印从第 1 字节到第 2 字节的字符串,b

    fmt.Println(s[0:4] + "好") // 连接字符串
    str := "你我皆完满," +
        "生在人世间。"
    fmt.Println(str)
}

由代码块可以看出,使用 + 连接字符串的时候,是可以跨行操作的;由于编译器会自动在行尾补全分号,+ 号必须要放在第一行。

除此以外,还可以通过使用 “==” 和 “<” 等比较运算符的方法逐字节的编码进行比较。

func main() {
    s := "你"
    t := "好"
    if s < t { // 使用比较运算符计算字节长度
        fmt.Print(s[0], t[0])
        fmt.Println(s[1], t[1])
        fmt.Println(s[2], t[2])
    }
    a := "a"
    b := "b"
    if a < b {fmt.Println(a[0], "小于", b[0])
    }
}
  • 字符串遍历

(施工中)

  • 字符串修改

在 Go 语言中,字符串的内容不能修改,也就不能用 s[i] 这种方式修改字符串的 UTF- 8 编码,如果确实要修改,那么可以将字符串的内容复制到另一个可写的变量中,然后再进行修改 。一般使用 []bute []rune 进行修改。

如果要对字符串中的 字节 进行修改,就转换成 []byte 格式;如果要对字符串中的 字符 进行修改,就转换成 []rune 格式。在转换的过程中会自动复制数据。

// 使用[]byte 修改字符串 s 的字节
func main() {
    s := "Hello 世界"
    b := []byte(s)        
    b[5] = ','            // 修改第 5 字节的值
    fmt.Printf("%s\n", s) // 打印修改前字符串
    fmt.Printf("%s\n", b) // 打印修改后的字符串
}
// 使用[]rune 修改字符串 s 中的字符
func main() {
    s := "Hello 世界!"
    r := []rune(s)
    r[6] = '中' // 修改字符串中的字符
    r[7] = '国'
    fmt.Println(s)         // 打印修改前字符串的字符
    fmt.Println(string(r)) // 打印修改后字符串的字符
}

Go 语言中的字符串是根据长度限定的,而非特殊字符 0。string 类型的 0 值是长度为 0 的字符串,即空字符串 ””。

  • 想要获取字符串所占字节长度的方法,一般是可以通过比较运算符(==, !=, <, <=, >=, >)在内存中按字节比较来实现字符串的对比,再使用 len() 函数获取字符串所占的字节长度。
  • 字符串的内容可以通过使用 标准索引法 来获取。需要注意的是,标准索引法只适用于 纯 ASCII 码的字符串 有效。
  • 注意,获取字符串中某个字节的地址是非法的!例如:&str[i]。

布尔型

布尔类型无法被其他类型复制,也不支持类型转换。Go 语言中只有 true 和 false 两个值。它的声明形式如下:

v := bool // 声明布尔类型
x := (1 == 2) // 编译器自动推导类型

当运算符两边的值 完全相同时(值相同,数据类型相同)时就会返回 true,否则返回 false。如果值的类型是接口,它们必须实现了相同类型的接口才能比较。如果类型不同,则必须使用类型转换之后才能比较。

布尔类型运算

二元运算符:和 &&、或 ||、相等 ==、不等!=
一元运算符:非!

  • 非运算符:!

使用 T 代表符合 true 的语句,使用 F 代表附和 false 的语句
非运算符 用于取得与布尔值相反的结果

!T -> false
!F -> true
  • 和运算符:&&

和运算符 用于当两边的值都为 true 时,结果才是 true

T && T -> true
T && F -> false
F && T -> false
F && F -> false
  • 或运算符:||

或运算符 用于当两边值都为 false 时,结果才是 false

T || T -> true
T || F -> true
F || T -> true
F || F -> false

在 Go 语言中,&& 和 || 是具有 快捷性质 的运算符,当左边表达式的值确立时(&& 左边为 false,|| 左边为 true),运算符右边的表达式就不会被执行。利用这个性质,我们应该将计算过程较为复杂的表达式放在运算符的右边,减少不必要的计算。

在格式化输出时,可以使用 %t 来表示要输出的值为布尔型。

退出移动版