Golang语言社区--Go语言基础第四节类型

大家好,我是Golang语言社区主编彬哥,这节给大家讲解Go语言中的类型。

Go语言中使用的类型包括:

基础类型

布尔类型(bool)

var b1 bool = true

整型

var v1 int = 12

浮点类型(float32、float64)

var f1 float32 = 12.0

复数类型(complex64、complex128)

var c1 complex64 = 3.2 + 12i

字符串(string)

var s string = “sina”

字符类型(rune)

代表单个的unicode字符

错误类型(error)

复合类型

指针(pointer)

数组(array)

[32] byte

切片(slice)

字典(map)

var word_count map[string] int

通道(chan)

用于协程间通信

结构体(struct)

接口(interface)

1、布尔类型

布尔类型不能接受其它类型的赋值,不支持自动或强制的类型转换,以下的示例是一些错误的用法:

var golang bool
golang = 1          // 错误
golang = bool(1)    // 错误

以下的用法是正确的:

var golang bool
golang = (1!=0)

2、整型

类型

长度

值范围

int8

1

-128 ~ 127

uint8(即byte)

1

0 ~ 255

int16

2

-32768 ~ 32767

uint16

2

0 ~ 65535

int32

4

-2147483648 ~ 2147483647

uint32

4

0 ~ 4294967295

int64

8

(-2^63) ~ (2^63-1)

uint64

8

0 ~ (2^64-1)

int

平台相关

平台相关

uint

平台相关

平台相关

uintptr

同指针

32位平台下为4字节,64位平台下为8字节

需要注意的是,int和int32是不同的类型, 不能相互赋值,例如:

var val2 int32
val1 := 64     // val1会被自动推导为int类型
var2 = val1    // error
var2 = int32(val1)  // ok

此外,不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较,但各种类型的整型变量都可以直接与字面常量(literal)进行比较,比如:

var i int32
var j int64

i,j = 1,2 

if i==j {         // error
    fmt.Println("i and j are equal.") 
}

if i==1 || j==2 {     // ok
    fmt.Println("i and j are equal.") 
}   

3、浮点型

Go语言中的float32和float64分别等价于C语言的float、double类型;

var i float32 = 12.1 
j := 64.0      // 自动推导为float64类型
j = i        // error
j = float64(i)  // ok  

判断两个浮点数是否相等,是根据不同精度来的:

import "math"

func IsEqual(f1, f2, p float64) bool {
    return math.Fdim(f1, f2) < p
}

其中,p是用户自定义的比较精度,比如p=0.00001。

4、字符类型

在Go语言中支持两个字符类型,一个是byte(实际上是uint8的别名),代表UTF-8字符串的单个字节的值;另一个是rune,代表单个Unicode字符。

关于rune相关的操作,可查阅Go标准库的unicode包;另外unicode/utf8包也提供了UTF8和Unicode之间的转换。

5、字符串

字符串支持下标读取操作:

str := "Hello world"
ch := str[0]
fmt.Printf("The length of \"%s\" is %d\n", str, len(str))
fmt.Printf("The 1st character of \"%s\" is '%c'\n", str, ch)

但字符串的内容在初始化后不能被修改,例如:

str := "Hello world"
str[0] = 'X'    // error

常用的字符串操作:

操作

含义

s1 + s2

字符串连接

len(s)

字符串长度

s[i]

取字符

字符串遍历有两种方式:

str := "Hello,世界"

// 以字节数组的方式遍历

for i := 0; i<len(str); i++ {
  ch := str[i]
  fmt.Println(i, ch)
}

 

// 以unicode字符方式遍历,每个字符的类型是rune

for i, ch := range str {
  fmt.Println(i, ch) 
}

 

6、数组

数组的声明方法比较多,比如:

[32] byte                // 字节数组
[2*N] struct {x, y int 32}     // 结构体数组
[1000] *float64           // 指针数组
[3][5] int             // 二维数组
[2][2][2] float64   

在声明数组时长度可以为一个常量或一个常量表达式,数组长度在定义以后就不可以再改变。

数组支持按下标读写元素,也支持range关键字的遍历,例如:

var array = [5] int {10,20,30,40,50}

for i, v := range array {
    array[i] = v*2;
}

for i, v := range array {
    fmt.Println(i, v) 
}

另外,数组是值类型,如果将数组作为函数参数传递,则在函数调用的时候该参数将发生数据复制,因此,在函数体中无法修改传入的数组的内容。

7、slice

数组切片的数据结构可以抽象为以下3个变量:

  • 一个指向原生数组的指针;
  • 数组切片中的元素个数;
  • 数组切片已分配的存储空间;

数组切片类似于C++中STL的std::vector<>,支持动态扩展数组,并且可以被作为函数参数传递而不会导致元素被复制。

创建数组切片有下面多种方式:

1、基于数组创建的方式

var myArray [10] int = [10] int {1,2,3,4,5,6,7,8,9,10}

var s1 = myArray[:]    // 基于myArray的所有元素创建数组切片
var s2 = myArray[:5]   // 基于myArray的前5个元素创建数组切片
var s3 = myArray[5:]   // 基于myArray从第5个元素开始的所有元素创建数组切片

2、直接创建数组切片的方式

s1 := make([] int,5)    // 创建一个初始元素个数为5的数组切片,元素初始值为0
s2 := make([] int,5, 10) // 创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间
s3 := []int{1,2,3,4,5}  // 创建并初始化包含5个指定元素的数组切片

3、基于数组切片创建的方式

oldSlice := []int{1,2,3,4,5}
newSlice := oldSlice[:3]

操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len()获取元素个数,并支持使用range关键字来快速遍历所有元素。

数组切片支持可动态增减元素,内置的cap()和len()函数,分别返回数组切片分配的空间大小、当前存储的元素个数。

s := make([] int,5, 10)
fmt.Println("len(s)=",len(s))   // 5
fmt.Println("cap(s)=",cap(s))   // 10

使用append函数可以在数组切片尾端添加新元素:

s = append(s, 1,2,3)

如果追加的内容长度超过当前已分配的存储空间(即cap()返回值),数组切片会自动分配一块足够大的内存。

还可以将另一个数组切片追加到一个数组切片末端:

s2 := []int{8,9,10}
s = append(s, s2...)  // s2后面的省略号必须要有

数组切片的复制,如果两个slice不一样大,就会按其中较小的slice的元素个数进行复制,例如:

s1 := []int {1,2,3,4,5}
s2 := []int {5,4,7}
copy(s1, s2)  //只复制s2的3个元素到s1的前3个位置
copy(s2, s1)  //只复制s1的前3个元素到s2中

8、map

map是key-value结构的一个字典,类似于C++中STL的std::map<>。

例子:

type PersonInfo struct {
    ID string
    Name string
    Address string
}


func main() {
    var personDB map[string] PersonInfo      // 变量声明
    personDB = make(map[string] PersonInfo)    // 变量创建

    personDB["1"] = PersonInfo{"12345","Tom","Room 203"}  // 增加了一个键

    person, ok := personDB["1"]                // 查找
    if ok {
        fmt.Println("found person", person.Name, "with ID 1")
    } else {
        fmt.Println("Did not find person with ID 1")
    }

  delete(personDB, "1")        // 删除一个键
}

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 zhuanlan_guanli@qq.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Coding迪斯尼

自制Monkey语言编译器:解释执行return语句和错误处理控制

945
来自专栏维C果糖

史上最简单的 MySQL 教程(四十三)「函数」

函数,就是将一段代码封装到一个结构中,在需要执行该段代码的时候,直接调用该结构(函数)执行即可。此操作,实现了代码的复用。在 MySQL 中,函数有两种,分别为...

3606
来自专栏开发与安全

从零开始学C++之标准库类型(一):string 类简介和例程

一、标准库string类型 string类型支持长度可变的字符串,C++标准库将负责管理与存储字符相关的内存,以及提供各种有用的操作 ,在VC中直接F1查看 ...

2060
来自专栏测试开发架构之路

总结了一些指针易出错的常见问题(四)

指针与结构体 简介:我们可以使用C的结构体来表示数据结构元素,比如链表或树的节点,指针是把这些元素联系到一起的纽带。 typedef struct _pers...

2717
来自专栏coding for love

JS原生引用类型解析7-Promise类型

ES6引入了一个全新的对象Promise,用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。Promise最直接的好处就是链式调用,另外在错误捕获上...

391
来自专栏Laoqi's Linux运维专列

python3–复习+正则

4338
来自专栏Python小屋

《Python程序设计》判断题1-240题

1、Python是一种跨平台、开源、免费的高级动态编程语言。(对) 2、Python 3.x完全兼容Python 2.x。(错) 3、Python 3.x和Py...

3027
来自专栏小詹同学

Python 3 入门 ,看这篇就够了 。

Python 是一种高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python 由 Guido van Rossum 于 1989 年底在荷兰国家数...

682
来自专栏Java帮帮-微信公众号-技术文章全总结

04.Java对象和类

04.Java对象和类 Java 对象和类 Java作为一种面向对象语言。支持以下基本概念: 多态 继承 封装 抽象 类 对象 实例 方法 重载 本节我们重点研...

4116
来自专栏我的博客

init,__construct区别以及PHP魔术方法大汇总

init()是框架设置为初始化函数,当然框架内部还是用的___construct()内置函数;如果你是框架开发者,你当然也可以把初始化函数写成__init(),...

2865

扫描关注云+社区