4.Golang数据类型

栏目: Go · 发布时间: 6年前

内容简介:Go 语言数据类型包含基础类型和复合类型两大类。基础数据类型包括:布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。复合数据类型包括:指针、数组、切片、字典、通道、结构体、接口。

Go 语言数据类型包含基础类型和复合类型两大类。

基础数据类型包括:布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。

复合数据类型包括:指针、数组、切片、字典、通道、结构体、接口。

Go 语言在声明变量时会默认给变量赋个当前类型的空值,声明变量的方式:

声明方式 说明
var 变量名 <变量类型> 声明单个变量
var 变量名1, 变量名2,... <变量类型> 声明多个同类型变量
变量名 := 值 声明变量,并赋值;Go 语言会根据所赋值推断变量的类型
变量名1, 变量名2,... := 值1, 值2,... 声明多个同类型变量并赋值,几个变量必须赋几个值

一、布尔类型 (bool)

值:true 和 false,默认值为 false

package main

import "fmt"

func main() {
    var v1, v2 bool         // 声明变量,默认值为 false
    v1 = true               // 赋值
    v3, v4 := false, true   // 声明并赋值

    fmt.Print("v1:", v1)   // v1 输出 true
    fmt.Print("\nv2:", v2) // v2 没有重新赋值,显示默认值:false
    fmt.Print("\nv3:", v3) // v3 false
    fmt.Print("\nv4:", v4) // v4 true
}

二、数字类型

数字类型比较多,默认值都是 0。定义 int 类型时,默认根据系统类型设置取值范围,32位系统与 int32 的值范围相同,64位系统与 int64 的值范围相同。见下表:

类型 名称 存储空间 值范围 数据级别
uint8 无符号8位整形 8-bit 0 ~ 255
uint16 无符号16位整形 16-bit 0 ~65535 6万多
uint32 无符号32位整形 32-bit 0 ~ 4294967295 40多亿
uint64 无符号64位整形 64-bit 0 ~ 18446744073709551615 死了都不会溢出
int8 8位整形 8-bit -128 ~ 127 正负百
int16 16位整形 16-bit -32768 ~ 32767 正负3万多
int32 32位整形 32-bit -2147483648 ~ 2147483647 正负20多亿
int64 64位整形 64-bit -9223372036854775808 ~ 9223372036854775807 正负大到没概念
int 系统决定 系统决定 32位系统为 int32 的值范围,64位系统为 int64 的值范围
-
float32 32位浮点数 32-bit IEEE-754 1.401298464324817070923729583289916131280e-45 ~ 3.402823466385288598117041834516925440e+38 精度6位小数
float64 64位浮点数 64-bit IEEE-754 4.940656458412465441765687928682213723651e-324 ~ 1.797693134862315708145274237317043567981e+308 精度15位小数
-
complex64 复数,含 float32 位实数和 float32 位虚数 64-bit 实数、虚数的取值范围对应 float32
complex128 复数,含 float64 位实数和 float64 位虚数 128-bit 实数、虚数的取值范围对应 float64
-
byte 字符型,unit8 别名 8-bit 表示 UTF-8 字符串的单个字节的值,对应 ASCII 码的字符值
rune 字符型,int32 别名 32-bit 表示 单个 Unicode 字符
uintptr 无符号整型 由系统决定 能存放指针地址即可
package main

import "fmt"

func main() {
    // 无符号整形,默认值都是0
    var u8 uint8
    var u16 uint16
    var u32 uint32
    var u64 uint64
    fmt.Printf("u8: %d, u16: %d, u32: %d, u64: %d\n", u8, u16, u32, u64) // 默认值都为0
    u8 = 255
    u16 = 65535
    u32 = 4294967295
    u64 = 18446744073709551615
    fmt.Printf("u8: %d, u16: %d, u32: %d, u64: %d\n", u8, u16, u32, u64)

    // 整型
    var i8 int8
    var i16 int16
    var i32 int32
    var i64 int64
    fmt.Printf("i8: %d, i16: %d, i32: %d, i64: %d\n", i8, i16, i32, i64) // 默认值都为0
    i8 = 127
    i16 = 32767
    i32 = 2147483647
    i64 = 9223372036854775807
    fmt.Printf("i8: %d, i16: %d, i32: %d, i64: %d\n", i8, i16, i32, i64)

    // int 型,取值范围32位系统为 int32,64位系统为 int64,取值相同但为不同类型
    var i int
    //i = i32 // 报错,编译不通过,类型不同
    //i = i64 // 报错,编译不通过,类型不同
    i = -9223372036854775808
    fmt.Println("i: ", i)

    // 浮点型,f32精度6位小数,f64位精度15位小数
    var f32 float32
    var f64 float64
    fmt.Printf("f32: %f, f64: %f\n", f32, f64) // 默认值都为 0.000000
    f32 = 1.12345678
    f64 = 1.12345678901234567
    fmt.Printf("f32: %v, f64: %v\n", f32, f64) // 末位四舍五入,输出:f32: 1.1234568, f64: 1.1234567890123457

    // 复数型
    var c64 complex64
    var c128 complex128
    fmt.Printf("c64: %v, c128: %v\n", c64, c128) // 实数、虚数的默认值都为0
    c64 = 1.12345678 + 1.12345678i
    c128 = 2.1234567890123456 + 2.1234567890123456i
    fmt.Printf("c64: %v, c128: %v\n", c64, c128) // 输出:c64: (1.1234568+1.1234568i), c128: (2.1234567890123457+2.1234567890123457i)

    // 字符型
    var b byte                                       // uint8 别名
    var r1, r2 rune                                  // uint16 别名
    fmt.Printf("b: %v, r1: %v, r2: %v\n", b, r1, r2) // 默认值为0
    b = 'a'
    r1 = 'b'
    r2 = '字'
    fmt.Printf("b: %v, r1: %v, r2: %v\n", b, r1, r2) // 输出:b: 97(ASCII表示的数), r1: 98(utf-8表示的数), r2: 23383 (utf-8表示的数)

    b = u8
    r1 = i32
    fmt.Printf("b: %v, r1: %v\n", b, r1) // 输出:b: 255, r1: 2147483647

    // 指针地址
    var p uintptr
    fmt.Printf("p: %v\n", p) // 默认值为0
    p = 18446744073709551615 // 64位系统最大值
    //p = 18446744073709551616 // 报错:超出最大值
    fmt.Printf("p: %v\n", p)

}

三、字符串 (string)

Go 语言默认编码都是 UTF-8。

package main

import "fmt"

func main() {
    var str1 string // 默认值为空字符串 ""
    str1 = `hello world`
    str2 := "你好世界"

    str := str1 + " " + str2 // 字符串连接
    fmt.Println(str1)
    fmt.Println(str2)
    fmt.Println(str) // 输出:hello world 你好世界

    // 遍历字符串
    l := len(str)
    for i := 0; i < l; i++ {
        chr := str[i]
        fmt.Println(i, chr) // 输出字符对应的编码数字
    }
}

四、指针(pointer)

指针其实就是指向一个对象(任何一种类型数据、包括指针本身)的地址值,对指针的操作都会映射到指针所指的对象上。

package main

import (
    "fmt"
)

func main() {
    var p *int // 定义指向int型的指针,默认值为空:nil

    // nil指针不指向任何有效存储地址,操作系统默认不能访问
    //fmt.Printf("%x\n", *p) // 编译报错

    var a int = 10
    p = &a        // 取地址
    add := a + *p // 取值

    fmt.Println(a)   // 输出:10
    fmt.Println(p)   // 输出:0xc0420080b8
    fmt.Println(add) // 输出:20
}

五、数组(array)

数组为一组相同数据类型数据的集合,数组定义后大小固定,不能更改,每个元素称为 element ,声明的数组元素默认值都是对应类型的0值。而且数组在 Go 语言中是一个值类型(value type), 所有值类型变量在赋值和作为参数传递时都会产生一次复制动作 ,即对原值的拷贝。

package main

import "fmt"

func main() {
    // 1.声明后赋值
    // var <数组名称> [<数组长度>]<数组元素>
    var arr [2]int   // 数组元素的默认值都是 0
    fmt.Println(arr) // 输出:[0 0]
    arr[0] = 1
    arr[1] = 2
    fmt.Println(arr) // 输出:[1 2]

    // 2.声明并赋值
    // var <数组名称> = [<数组长度>]<数组元素>{元素1,元素2,...}
    var intArr = [2]int{1, 2}
    strArr := [3]string{`aa`, `bb`, `cc`}
    fmt.Println(intArr) // 输出:[1 2]
    fmt.Println(strArr) // 输出:[aa bb cc]

    // 3.声明时不设定大小,赋值后语言本身会计算数组大小
    // var <数组名称> [<数组长度>]<数组元素> = [...]<元素类型>{元素1,元素2,...}
    var arr1 = [...]int{1, 2}
    arr2 := [...]int{1, 2, 3}
    fmt.Println(arr1) // 输出:[1 2]
    fmt.Println(arr2) // 输出:[1 2 3]
    //arr1[2] = 3 // 编译报错,数组大小已设定为2

    // 4.声明时不设定大小,赋值时指定索引
    // var <数组名称> [<数组长度>]<数组元素> = [...]<元素类型>{索引1:元素1,索引2:元素2,...}
    var arr3 = [...]int{1: 22, 0: 11, 2: 33}
    arr4 := [...]string{2: "cc", 1: "bb", 0: "aa"}
    fmt.Println(arr3) // 输出:[11 22 33]
    fmt.Println(arr4) // 输出:[aa bb cc]

    // 遍历数组
    for i := 0; i < len(arr4); i++ {
        v := arr4[i]
        fmt.Printf("i:%d, value:%s\n", i, v)
    }
}

六、切片(slice)

因为数组的长度定义后不可修改,所以需要切片来处理可变长数组数据。切片可以看作是一个可变长的数组,是一个引用类型。它包含三个数据:1.指向数组的指针,2.切片中的元素,3.切片的大小

声明一个切片,或从数组中取一段作为切片数据:

package main

import "fmt"

func main() {
    var sl []int             // 声明一个切片
    sl = append(sl, 1, 2, 3) // 往切片中追加值
    fmt.Println(sl)          // 输出:[1 2 3]

    var arr = [5]int{1, 2, 3, 4, 5} // 初始化一个数组
    var sl1 = arr[0:2]              // 冒号:左边为起始位(包含起始位数据),右边为结束位(不包含结束位数据);不填则默认为头或尾
    var sl2 = arr[3:]
    var sl3 = arr[:5]

    fmt.Println(sl1) // 输出:[1 2]
    fmt.Println(sl2) // 输出:[4 5]
    fmt.Println(sl3) // 输出:[1 2 3 4 5]

    sl1 = append(sl1, 11, 22) // 追加元素
    fmt.Println(sl1)          // 输出:[1 2 11 22]
}

使用 make 直接创建切片,语法:make([]类型, 大小,预留空间大小)

package main

import "fmt"

func main() {
    var sl1 = make([]int, 5)          // 定义元素个数为5的切片
    sl2 := make([]int, 5, 10)         // 定义元素个数5的切片,并预留10个元素的存储空间(预留空间不知道有什么用?)
    sl3 := []string{`aa`, `bb`, `cc`} // 直接创建并初始化包含3个元素的数组切片

    fmt.Println(sl1, len(sl1)) // 输出:[0 0 0 0 0] 5
    fmt.Println(sl2, len(sl2)) // 输出:[0 0 0 0 0] 5
    fmt.Println(sl3, len(sl3)) // [aa bb cc] 3

    sl1[1] = 1 // 声明或初始化大小中的数据,可以指定赋值
    sl1[4] = 4
    //sl1[5] = 5 // 编译报错,超出定义大小
    sl1 = append(sl1, 5)       // 可以追加元素
    fmt.Println(sl1, len(sl1)) // 输出:[0 1 0 0 4 5] 6

    sl2[1] = 1
    sl2 = append(sl2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
    fmt.Println(sl2, len(sl2)) // 输出:[0 1 0 0 0 1 2 3 4 5 6 7 8 9 10 11] 16

    // 遍历切片
    for i := 0; i < len(sl2); i++ {
        v := sl2[i]
        fmt.Printf("i: %d, value:%d \n", i, v)
    }
}

七、字典(map)

map 是一种键值对的无序集合,与 slice 类似也是一个引用类型。map 本身其实是个指针,指向内存中的某个空间。

声明方式与数组类似,声明方式: var 变量名 map[key类型]值类型 或直接使用 make 函数初始化: make(map[key类型]值类型)

其中 key 值可以是任何可以用 == 判断的值类型,对应的值类型没有要求。

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // 声明后赋值
    var m map[int]string
    fmt.Println(m) // 输出空的map:map[]
    //m[1] = `aa`    // 向未初始化的map中赋值报错:panic: assignment to entry in nil map

    // 声明并初始化,初始化使用{} 或 make 函数(创建类型并分配空间)
    var m1 = map[string]int{}
    var m2 = make(map[string]int)
    m1[`a`] = 11
    m2[`b`] = 22
    fmt.Println(m1) // 输出:map[a:11]
    fmt.Println(m2) // 输出:map[b:22]

    // 初始化多个值
    var m3 = map[string]string{"a": "aaa", "b": "bbb"}
    m3["c"] = "ccc"
    fmt.Println(m3) // 输出:map[a:aaa b:bbb c:ccc]

    // 删除 map 中的值
    delete(m3, "a") // 删除键 a 对应的值
    fmt.Println(m3) // 输出:map[b:bbb c:ccc]

    // 查找 map 中的元素
    v, ok := m3["b"]
    if ok {
        fmt.Println(ok)
        fmt.Println("m3中b的值为:", v) // 输出:m3中b的值为: bbb
    }
    // 或者
    if v, ok := m3["b"]; ok { // 流程处理后面讲
        fmt.Println("m3中b的值为:", v) // 输出:m3中b的值为: bbb
    }

    fmt.Println(m3["c"]) // 直接取值,输出:ccc

    // map 中的值可以是任意类型
    m4 := make(map[string][5]int)
    m4["a"] = [5]int{1, 2, 3, 4, 5}
    m4["b"] = [5]int{11, 22, 33}
    fmt.Println(m4)                // 输出:map[a:[1 2 3 4 5] b:[11 22 33 0 0]]
    fmt.Println(unsafe.Sizeof(m4)) // 输出:8,为8个字节,map其实是个指针,指向某个内存空间
}

八、通道(channel)

说到通道 channel,则必须先了解下 Go 语言的 goroutine 协程(轻量级线程)。channel 就是为 goroutine 间通信提供通道。goroutine 是 Go 语言提供的语言级的协程,是对 CPU 线程和调度器的一套封装。

channel 也是类型相关的,一个 channel 只能传递一种类型的值。

声明: var 通道名 chan 通道传递值类型 或 make 函数初始化: make(chan 值类型, 存储空间大小)

package main

import (
    "fmt"
    "time"
)

func main() {
    var ch1 chan int            // 声明一个通道
    ch1 = make(chan int)        // 未初始化的通道不能存储数据,初始化一个通道
    ch2 := make(chan string, 2) // 声明并初始化一个带缓冲空间的通道

    // 通过匿名函数向通道中写入数据,通过 <- 方式写入
    go func() { ch1 <- 1 }()
    go func() { ch2 <- `a` }()

    v1 := <-ch1 // 从通道中读取数据
    v2 := <-ch2
    fmt.Println(v1) // 输出:1
    fmt.Println(v2) // 输出:a

    // 写入,读取通道数据
    ch3 := make(chan int, 1) // 初始化一个带缓冲空间的通道
    go readFromChannel(ch3)
    go writeToChannel(ch3)

    // 主线程休眠1秒,让出执行权限给子 Go 程,即通过 go 开启的 goroutine,不然主程序会直接结束
    time.Sleep(1 * time.Second)
}

func writeToChannel(ch chan int) {
    for i := 1; i < 10; i++ {
        fmt.Println("写入:", i)
        ch <- i
    }
}

func readFromChannel(ch chan int) {
    for i := 1; i < 10; i++ {
        v := <-ch
        fmt.Println("读取:", v)
    }
}

// ------  输出:--------
1
a
写入: 1
写入: 2
写入: 3
读取: 1
读取: 2
读取: 3
写入: 4
写入: 5
写入: 6
读取: 4
读取: 5
读取: 6
写入: 7
写入: 8
写入: 9
读取: 7
读取: 8
读取: 9

goroutine 和 channel 的详细讲解待补充。

九、结构体(struct)

结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员。

package main

import "fmt"

// 定义一个结构体 person
type person struct {
    name string
    age  int
}

func main() {
    var p person   // 声明一个 person 类型变量 p
    p.name = "max" // 赋值
    p.age = 12
    fmt.Println(p) // 输出:{max 12}

    p1 := person{name: "mike", age: 10} // 直接初始化一个 person
    fmt.Println(p1.name)                // 输出:mike

    p2 := new(person) // new函数分配一个指针,指向 person 类型数据
    p2.name = `张三`
    p2.age = 15
    fmt.Println(*p2) // 输出:{张三 15}
}

十、接口(interface)

十一、错误


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro JavaScript Design Patterns

Pro JavaScript Design Patterns

Dustin Diaz、Ross Harmes / Apress / 2007-12-16 / USD 44.99

As a web developer, you’ll already know that JavaScript™ is a powerful language, allowing you to add an impressive array of dynamic functionality to otherwise static web sites. But there is more power......一起来看看 《Pro JavaScript Design Patterns》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具