美文网首页
【Go语言】编程系列 - 顺序编程-2

【Go语言】编程系列 - 顺序编程-2

作者: 水瓶座男生 | 来源:发表于2018-06-13 16:26 被阅读28次

第2章 顺序编程

2.1 变量

  • 变量是几乎所有编程语言中基本的组成元素
  • 程序可以通过定义一个变量来申请一块数据存储空间
2.1.1 变量声明
  • Go语言引入了 关键字var,而类型信息放在变量名之后
var v1 int
var v2 string 
var v3 [10]int   // 数组 
var v4 []int    // 数组切片
var v5 struct {   
f int 
} 
var v6 *int    // 指针
var v7 map[string]int // map,key为string类型,value为int类型 
var v8 func(a int) int

var (
    v1 int
    v2 string
)

2.1.2 变量初始化
- var v1 int = 10 //正确的使用方式1
- var v2 = 10 // 正确的使用方式2,编译器可以自动推倒出v2的类型
v3:=10 // 正确的使用方式3,编译器可以自动推导出v3的类型
2.1.3 变量初始化
  • 对于声明变量时需要进行初始化的场景,var关键字可以保留,但不再是必要的元素
var v10  int
v10 =123
  • Go语言的变量赋值,支持多重赋值功能
  • 比如下面这个交换i和j变量的语句: i,j = j,i
2.1.4 匿名变量
func GetName() (firstName, lastName, nickName string) {  return "May", "Chan", "Chibi Maruko" }
若只想获得nickName,则函数调用语句可以用如下方式编写: 
_, _, nickName := GetName() 

2.2 常量

  • 在Go语言中,常量是指编译期间就已知且不可改变的值
  • 常量可以是数值类型(包括整型、 浮点型和复数类型)、布尔类型、字符串类型等.
2.2.1 字面常量
  • 字面常量(literal),是指程序中硬编码的常量
2.2.2 常量定义
  • 通过const关键字,你可以给字面常量指定一个友好的名字
const Pi float64 = 3.14159265358979323846  
const zero = 0.0             // 无类型浮点常量 
const (     
 size int64 = 1024     
 eof = -1                // 无类型整型常量 
) 
const u, v float32 = 0, 3    // u = 0.0, v = 3.0,常量的多重赋值 const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo", // 无类型整型和字符串常量 Go
  • Go的常量定义可以限定常量类型,但不是必需的。
  • 如果定义常量时没有指定类型,那么它 与字面常量一样,是无类型常量。
  • 由于常量的赋值是一个编译期行为,所以右值不能出现任何需要运行期才能得出结果的表达式

2.2.3 预定义常量

  • Go语言预定义了这些常量:true、false和iota。
  • iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被 重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。

2.2.4 枚举

const (     
Sunday = iota     
Monday     
Tuesday     
Wednesday     
Thursday     
Friday     
Saturday     numberOfDays        // 这个常量没有导出  )
  • 同Go语言的其他符号(symbol)一样,以大写字母开头的常量在包外可见
  • 以上例子中numberOfDays为包内私有,其他符号则可被其他包访问。

2.3 类型

  • Go语言内置以下这些基础类型:
    • 布尔类型:bool
    • 整形:int8 、byte 、int16 、int 、uint 、uintptr等
    • 浮点类型:float32、float64
    • 复数类型:complex64、complex128
    • 字符串 :string
    • 字符类型 : rune
    • 错误类型:error
  • 此外,Go语言也支持以下这些复合类型:
    • 指针(pinter)
    • 数组(array)
    • 切片(slice)
    • 字典(map)
    • 通道(chan)
    • 结构体(stuct)
    • 接口(interface)
2.3.1 布尔类型
  • 布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换
  • 可赋值为预定义的true和 false
//示例代码
var v1 bool
v1 =true
v2 := (1==2)
2.3.2 整形
  • 整型是所有编程语言里基础的数据类型。
类型 长度(字节) 值范围
int8 1 -128~127
uint8(即byte) 1 0~255
int16 2 -32 768 ~ 32 767
uint16 2 0 ~ 65 535
int32 4 -2 147 483 648 ~ 2 147 483 647
uint32 4 0 ~ 4 294 967 295
int64 8 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
uint64 8 0 ~ 18 446 744 073 709 551 615
int 平台相关 平台相关
uint 平台相关 平台相关
uintptr 同指针 在32位平台下为4字节,64位平台下为8字节
1. 类型表示
  • int和int32在Go语言里被认为是两种不同的类型,编译器也不会帮你自动 做类型转换
var value2 int32 
value1 := 64  // value1将会被自动推导为int类型 value2 = value1 // 编译错误 
value2 = int32(value1) // 编译通过 

  • 开发者在做强制类型转换时,需要注意数据长度被截短而发生的数据精度损失(比如 将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。
2. 数值运算
  • Go语言支持下面的常规整数运算:+、、*、/和%
3. 比较运算
  • Go语言支持以下的几种比较运算符:>、<、==、>=、<=和!=。这一点与大多数其他语言相 同,与C语言完全一致。
  • 两个不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较,但 各种类型的整型变量都可以直接与字面常量(literal)进行比较。
var i int32 
var j int64 
 
i, j = 1, 2 
 
if i == j {   // 编译错误     
fmt.Println("i and j are equal.")  
}   
 
if i == 1 || j == 2 { // 编译通过     fmt.Println("i and j are equal.")  
}
4. 位运算
  • Go语言支持表2-2所示的位运算符。
运算 含义 样例
x<<y 左移 124 << 2 // 结果为496
x >> y 右移 124 >> 2 // 结果为31
x ^ y 异或 124 ^ 2 // 结果为126
x & y 124 & 2 // 结果为0
x | y 124 | 2 // 结果为126
^x 取反 ^2 // 结果为-3

2.3.3 浮点型

  • 浮点型用于表示包含小数点的数据
1. 浮点数表示
  • Go语言定义了两个类型float32和float64
  • 其中float32等价于C语言的float类型, float64等价于C语言的double类型。
2. 浮点数比较
  • 因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等 是不可行的,这可能会导致不稳定的结果。
import "math" 
 
// p为用户自定义的比较精度,比如0.00001 
func IsEqual(f1, f2, p float64) bool {  
    return math.Fdim(f1, f2) < p  
}

2.3.4 复数类型

  • 复数实际上由两个实数(在计算机中用浮点数表示)构成
  • 一个表示实部(real),一个表示 虚部(imag)
1. 复数表示
var value1 complex64    // 由2个float32构成的复数类型 
value1 = 3.2 +12i
value2 :=3.2 +12i
value3 :=complex(3.2,12)
2.实部与虚部
  • 对于一个复数z = complex(x, y),就可以通过Go语言内置函数real(z)获得该复数的实 部,也就是x,通过imag(z)获得该复数的虚部,也就是y。

2.3.5 字符串

var str string  // 声明一个字符串变量 
str ="hello word"
ch:=str[0] //取字符串的第一个字符
fmt.Println("The length of \"%s\" is %d \n ",str,len(str))
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
  • 字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能在初始 化后被修改
1. 字符串操作
  • x+y 字符串链接
  • len(s) 字符串长度
  • s[i] 取字符
  • 更多字符串操作,请参考标准库strings包
2. 字符串遍历
  • Go语言支持两种方式遍历字符串
  • 一种是以字节数组的方式遍历
str := "Hello,世界" 
n := len(str) 
for i := 0; i < n; i++ {    
ch := str[i] // 依据下标取字符串中的字符,类型为byte     fmt.Println(i, ch)
}
str := "Hello,世界" 
for i, ch := range str {   
fmt.Println(i, ch)//ch的类型为rune 
    
}
  • 以Unicode字符方式遍历时,每个字符的类型是rune(早期的Go语言用int类型表示Unicode 字符),而不是byte。

字符类型

  • 在Go语言中支持两个字符类型,一个是byte(实际上是uint8的别名),代表UTF-8字符的单个字节的值
  • 另一个是rune,代表单个Unicode字符
  • 关于rune相关的操作,可查阅Go标准库的unicode包。另外unicode/utf8包也提供了UTF8和Unicode之间的转换。

2.3.7 数组

  • 数组就是指一系列同一类型数据 的集合。数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数 组的长度。
  • 以下为一些常规的数组声明方法:
[32]byte     //长度为32的数组,每个元素为一个字节 
[2*N] struct {
    x,y int32
}
[1000] *float64 //指针数组
[3][5] int      //二维数组
[2][2][2] float64 //等同于[2]([2]([2]float64)) 

1. 元素访问
  • 可以使用数组下标来访问数组中的元素
for i := 0; i < len(array); i++ {  
    fmt.Println("Element", i, "of array is", array[i])  
}
  • Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素
for i, v := range array {     
    fmt.Println("Array element[", i, "]=", v)  
} 
2. 值类型
  • 在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。因此,在函数体中无法修改传入的数组的内容。
pacage main
import "fmt"

func modify (array [10] int) {
    array[0] =10
    fmt.Println("In modify (),array values : ", array)
}

funct main(){
    array := [5] int{1,2,3,4,5} //定义并初始化一个数组
    modify(array) //传递一个函数,并试图在函数体内修改这个数组内容
    fmt.Println("In main() , array values : " ,array)
}

2.3.8 数组切片

  • 数组的特点:数组的长度在定义之后无法再次修改;
  • 数组是值类型, 每次传递都将产生一份副本
  • 数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构
    • 数组切片的数据结构可以抽象为以下3个变量:
    • 一个指向原生数组的指针;
    • 数组切片中的元素个数;
    • 数组切片已分配的存储空间。
1. 创建数组切片 创建数组切片的方法
  • 创建数组切片的方法主要有两种——基于数组和直接创建,下面我们来简要介绍一下这两种方法

基于数组

  • 数组切片可以基于一个已存在的数组创建。
  • 数组切片可以只使用数组的一部分元素或者整个 数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片。
pacage main
import "fmt"

func main(){
    var myArray [10] int = [10]{1,2,3,4,5,6,7,8,9,10}
    
    var mySlice []int = myArray[:5]
    fmt.Println("Elements of myArray: ") 
     
    for _,v := range myArray {
        fmt.Print(v, " ") 
    }
    
    fmt.Println() 
}
  • Go语言支持用myArray[first:last]这样的方式来基于数组生成一 个数组切片,而且这个用法还很灵活
  • 基于myArray的所有元素创建数组切片: mySlice = myArray[:]
  • 基于myArray的前5个元素创建数组切片: mySlice = myArray[:5]
  • 基于从第5个元素开始的所有元素创建数组切片: mySlice = myArray[5:]
    直接创建
  • Go语言提供的内置函数make()可以用于 灵活地创建数组切片.
  • 创建一个初始元素个数为5的数组切片,元素初始值为0:
  • mySlice1 :=make ([]int ,5)
  • mySlice2 := make([]int, 5, 10)
  • mySlice3 := []int{1, 2, 3, 4, 5}
2. 元素遍历
  • 操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len() 函数获取元素个数,并支持使用range关键字来快速遍历所有元素
  • 传统的元素遍历方法如下:
for i:= 0;i<len(mySlice);i++ {
    fmt.Println("mySlice[",i,"]=",mySlice[i])
}
  • 使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引, 第二个是元素的值:
for i, v :=  range mySlice { 
    fmt.Println("mySlice[", i, "] =", v)  
}
3. 动态增减元素
  • 可动态增减元素是数组切片比数组更为强大的功能
  • 数组切片多了一个存储能力(capacity)的概念,即元素个数和分配的空间可以是两个不同的值
  • 数组切片支持Go语言内置的cap()函数和len()函数
  • cap()函数返回的是数组切片分配的空间大小,而len()函数返回的是 数组切片中当前所存储的元素个数。
package main 
 
import "fmt" 
 
func main() {     
mySlice := make([]int, 5, 10)  
    fmt.Println("len(mySlice):", len(mySlice))  
    fmt.Println("cap(mySlice):", cap(mySlice)) 
}
  • 新增元素,可以使用append()函数
  • mySlice = append(mySlice, 1, 2, 3) //从尾端给mySlice加上3个元素
  • 接将一个数组切片追加到另一个数组切片的末尾
  • mySlice2 := []int{8, 9, 10}
  • mySlice = append(mySlice, mySlice2...)
  • 在第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省 略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的 元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相 当于把mySlice2包含的所有元素打散后传入。
  • 数组切片会自动处理存储空间不足的问题。如果追加的内容长度超过当前已分配的存储空间 (即cap()调用返回的信息),数组切片会自动分配一块足够大的内存
4. 基于数组切片创建数组切片
oldSlice := []int{1, 2, 3, 4, 5} 
newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片
5. 内容复制
  • 数组切片支持Go语言的另一个内置函数copy(),用于将内容从一个数组切片复制到另一个 数组切片
  • slice1 := []int{1, 2, 3, 4, 5}
  • slice2 := []int{5, 4, 3}
  • copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
  • copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
  • 如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行 复制。

2.3.9 map

  • map是一堆键值对的未排序集合
package main
import "fmt"

type PersonInfo struct {
    ID string
    Name string
    Address string 
}

func main () {
    var personDB  map[string] PersonInfo
        personDB  = make(map[string] PersonInfo)
        
    personDB["123456"] = PersonInfo{"123456","TOM","ROOM203",...}
    personDB["1"]= PersonInfo{"1","jack","Room01",...}
    
    person , ok:=personDB["1234"]
    
    if ok {
        fmt.Println("Found person", person.Name, "with ID 1234.") 
        fmt.Println("Did not find person with ID 1234.") 
    }
}

1. 变量声明
  • var myMap map[string] PersonInfo
  • myMap是声明的map变量名,string是键的类型,PersonInfo则是其中所存放的值类型
2. 创建
  • 使用Go语言内置的函数make()来创建一个新map
  • myMap = make(map[string] PersonInfo)
  • 指定该map的初始存储能力:
  • myMap = make(map[string] PersonInfo, 100)
  • 创建并初始化map的代码如:
myMap = map[string] PersonInfo{ 
"1234": PersonInfo{"1", "Jack", "Room 101,..."}, 
} 
3. 元素赋值
  • 赋值过程非常简单明了,就是将键和值用下面的方式对应起来即可:
myMap["1234"] = PersonInfo{"1", "Jack", "Room 101,..."}
4. 元素删除
delete(myMap, "1234") 
5. 元素查找
comming song...

相关文章

网友评论

      本文标题:【Go语言】编程系列 - 顺序编程-2

      本文链接:https://www.haomeiwen.com/subject/qbojeftx.html