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")        // 删除一个键
}

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

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C++

python笔记:#011#循环

1742
来自专栏Python

Python内置函数property()使用实例

class Shuxing(): def __init__(self, size = 10): self.size = size ...

20110
来自专栏西安-晁州

golang学习之defer

golang中的defer通常用于执行一些资源释放性操作,比如open/close、connect/disconnect、lock/unlock等,对defer...

2040
来自专栏达摩兵的技术空间

前端面试题分享001

解释 :要注意的是函数中的this与运行环境强相关,与定义环境不相关。所以下面的代码段中,当直接通过对象属性方法中去调用时,其都可以访问到对象的属性,但是当其变...

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

JavaWeb03-轻松理解JS(Java真正的全栈开发)

? 一.js常用对象 ljs中的常见对象有以下几个: Boolean Number String Array 数组 Date 日期 Math 数学 RegEx...

28112
来自专栏十月梦想

JavaScript中类的创建以及类的传参

在之前(ES2015)以前我们常用构造函数来搞定一个事物类,通过new 这个构造函数实现类的功能!在ES6(ES2015)中已经可以使用类,下面我们看一下类如何...

872
来自专栏转载gongluck的CSDN博客

python笔记:#011#循环

循环 目标 程序的三大流程 while 循环基本使用 break 和 continue while 循环嵌套 01. 程序的三大流程 在程序开发中,一共有三种流...

3564
来自专栏web前端教室

web前端零基础课-0908*福祥-学习笔记

学了部分js内容后,完成了网站首页部分动态效果(搜索栏、侧边导航条、轮播图),先用最基本的,冗余最多的一步步实现;后面对Js进行了初步的封装,重新构建了Js文件...

813
来自专栏技术之路

golang 详解defer

defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体的"}"时...

3297
来自专栏Golang语言社区

Go语言基本语法

前面已经看到了Go程序的基本结构,所以这将是很容易理解Go编程语言等基本构建块。 Go令牌 Go程序包括各种令牌和令牌可以是一个关键字,一个标识符,常量,字符串...

2726

扫码关注云+社区