Go语言基础

常量

设置多个常量:

const (
Cyan = 0
Black = 1
White = 2
)

go语言的预定义常量:truefalseiota

iota 是一个可以被编译器修改的常量,在 const 关键字出现时被重置为 0,在下一个 const 出现之前,每出现一次 iota,其所代表的数字自动加 1。下面通过一个例子讲解 iota 的用法:

const (
a = iota //a == 0
b = iota //b ==1
c = iota //c == 2
)

const d = iota //d==0,因为const的出现,iota被重置为0

变量

变量声明var:=,二者只用一个

Go 声明和初始化变量的各种方法:

var a int
var b string
var c float64
var d [5] int //数组
var e [] int //数组切片
var f * int //正确
var v1 int = 5 //正确
var v2 = 5 //正确,编译器自动推导出V2类型
v3 := 5 //正确,编译器自动推导出V3的类型

数据类型

整型

Go 语言提供了 11 种整型,如下列表所示。可以通过unsafe.Sizeof(引入unsafe包)查看类型字节长度

类型 说明 字节长度
byte 等同于 uint8
int 依赖于不同平台下的实现,可以是 int32 或者 int64
int8 [-128, 127] 1
int16 [-32768, 32767] 2
int32 [-2147483648, 2147483647] 4
int64 [-9223372036854775808, 9223372036854775807] 8
rune 等同于 int32
uint 依赖于不同平台下的实现,可以是 uint32 或者 uint64
uint8 [0, 255]
uint16 [0, 65535]
uint32 [0, 4294967295]
uint64 [0, 18446744073709551615]
uintptr 一个可以恰好容纳指针值的无符号整型(对 32 位平台是 uint32, 对 64 位平台是 uint64)

浮点型

Go 语言提供了两种浮点类型和两种复数类型,具体如下:

类型 说明
float32 ±3.402 823 466 385 288 598 117 041 834 845 169 254 40x1038 计算精度大概是小数点后 7 个十进制数
float64 ±1.797 693 134 862 315 708 145 274 237 317 043 567 981x1038 计算精度大概是小数点后 15 个十进制数
complex32 复数,实部和虚部都是 float32
complex64 复数,实部和虚部都是 float64

布尔型

  • Go 语言提供了内置的布尔值 truefalse
  • 可以通过 !b 的方式反转变量 b 的真假
  • 布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。

字符串

字符串操作

字符串支持以下操作:

语法 描述
s += t 将字符串 t 追加到 s 末尾
s + t 将字符串 s 和 t 级联
s[n] 从字符串 s 中索引位置为 n 处的原始字节
s[n:m] 从位置 n 到位置 m-1 处取得的字符(字节)串
s[n:] 从位置 n 到位置 len(s)-1 处取得的字符(字节)串
s[:m] 从位置 0 到位置 m-1 处取得的字符(字节)串
len(s) 字符串 s 中的字节数
len([]rune(s)) 字符串 s 中字符的个数,可以使用更快的方法 utf8.RuneCountInString()
[]rune(s) 将字符串 s 转换为一个 unicode 值组成的串
string(chars) chars 类型是 []rune 或者 []int32, 将之转换为字符串
[]byte(s) 无副本的将字符串 s 转换为一个原始的字节的切片数组,不保证转换的字节是合法的 UTF-8 编码字节

格式化字符串

常用的格式化指令如下:

格式化指令 含义
%% % 字面量
%b 一个二进制整数,将一个整数格式化为二进制的表达方式
%c 一个 Unicode 的字符
%d 十进制数值
%o 八进制数值
%x 小写的十六进制数值
%X 大写的十六进制数值
%U 一个 Unicode 表示法表示的整形码值,默认是 4 个数字字符
%s 输出以原生的 UTF-8 字节表示的字符,如果 console 不支持 UTF-8 编码,则会输出乱码
%q 输出带引号的字符串及字面量,如fmt.Printf("%q\n", "hello\n;") // prints "hello\n;" \n is escaped here
%t 以 true 或者 false 的方式输出布尔值
%v 使用默认格式输出值,或者使用类型的 String() 方法输出的自定义值,如果该方法存在的话
%T 输出值的类型

常用的格式化指令修饰符如下:

  • 空白 如果输出的数字为负,则在其前面加上一个减号 -。如果输出的是整数,则在前面加一个空格。使用 %x 或者 %X 格式化指令输出时,会在结果之间添加一个空格。例如 fmt.Printf("% X", "实") 输出 E5 AE 9E。
  • #
    • %#o 输出以 0 开始的八进制数据。
    • %#x 输出以 0x 开始的十六进制数据。
  • + 让格式化指令在数值前面输出 + 号或者 - 号,为字符串输出 ASCII 字符(非 ASCII 字符会被转义),为结构体输出其字段名。
  • - 让格式化指令将值向左对齐(默认值为像右对齐)。
  • 0 让格式指令以数字 0 而非空白进行填充。

切片

值传递:形参是实参的拷贝,复制一份传递

指针传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

引用传递:形参是实参的“别名”

数组是按值传递的(即是传递的副本),而切片是引用类型,传递切片的成本非常小,而且是不定长的。可以理解为go的切片和数组共用同一片底层区域,只是按照索引划分区域起了别名。

切片语法

创建切片的语法:

  • make([ ]Type, length, capacity)
  • make([ ]Type, length) ——默认切片长度和容量一致
  • [ ]Type{}
  • [ ]Type{value1, value2, ..., valueN}
package main

import (
"fmt"
)

func main() {
a := [...]int{1,2,3,4,5,6,7} //a是一个int型数组
fmt.Printf("len and cap of array %v is: %d and %d\n", a, len(a), cap(a))//%v--原样输出
fmt.Printf("item in array: %v is:", a)
for _, value := range a {
fmt.Printf("% d", value)
}

fmt.Println()

s1 := a[3:6]
fmt.Printf("len and cap of slice1: %v is: %d and %d\n", s1, len(s1), cap(s1))
//len=3 cap=4
fmt.Printf("item in slice1: %v is:", s1)
for _, value := range s1 {
fmt.Printf("% d", value)
}

fmt.Println()

s1[0] = 456
fmt.Printf("item in array changed after changing slice: %v is:", s1)
for _, value := range a {
fmt.Printf("% d", value)
}

fmt.Println()

s3 := s1[:cap(s1)]
fmt.Printf("len and cap of slice3: %v is: %d and %d\n", s3, len(s3), cap(s3))
fmt.Printf("item in slice3: %v is:", s3)
for _, value := range s3 {
fmt.Printf("% d", value)
}

fmt.Println()

s2 := make([]int, 10, 20)
s2[4] = 5
fmt.Printf("len and cap of slice2: %v is: %d and %d\n", s2, len(s2), cap(s2))
fmt.Printf("item in slice2 %v is:", s2)
for _, value := range s2 {
fmt.Printf("% d", value)
}

fmt.Println()
}

输出结果为:

len and cap of array [1 2 3 4 5 6 7] is: 7 and 7
item in array: [1 2 3 4 5 6 7] is: 1 2 3 4 5 6 7
len and cap of slice1: [4 5 6] is: 3 and 4
item in slice1: [4 5 6] is: 4 5 6
item in array changed after changing slice: [456 5 6] is: 1 2 3 456 5 6 7
len and cap of slice3: [456 5 6 7] is: 4 and 4
item in slice3: [456 5 6 7] is: 456 5 6 7
len and cap of slice2: [0 0 0 0 5 0 0 0 0 0] is: 10 and 20
item in slice2 [0 0 0 0 5 0 0 0 0 0] is: 0 0 0 0 5 0 0 0 0 0

切片扩容

切片通过 append 扩容时,如果切片长度小于当前的容量,那么切片不会扩容,如果追加元素后切片长度大于当前的容量时,切片就会扩容,扩容机制如下:

  • 当扩容之后的元素长度小于 1024 时会以原切片容量的 2 倍的进行扩容;
  • 当扩容之后的元素长度大于 1024 时会以原切片容量的 1.25 倍的进行扩容;

更多扩容细节参照博客http://t.csdn.cn/zQmdq

相关文档

Go语言顺序编程

流程控制

if语句

注意}和else要在同一行

for语句

for { // 无限循环
block
}

for booleanExpression { // while循环,在Go语言中没有while关键字

}

for index, char := range aString { // 迭代字符串

}

for item := range aChannel { // 迭代通道

}

跳转语句——goto

func myfunc(){
i := 0
THIS: //定义一个THIS标签
fmt.Println(i)
i++
if i < 1 {
goto THIS //跳转到THIS标签
}
}

switch语句

类型选择:

func classchecker(items ...interface{}) { // 创建一个函数,该函数可以接受任意多的任意类型的参数
for i, x := range items {
switch x := x.(type) { // 创建了影子变量
case bool:
fmt.Printf("param #%d is a bool, value: %t\n", i, x)
case float64:
fmt.Printf("param #%d is a float64, value: %f\n", i, x)
case int, int8, int16, int32, int64:
fmt.Printf("param #%d is a int, value: %d\n", i, x)
case uint, uint8, uint16, uint32, uint64:
fmt.Printf("param #%d is a uint, value: %d\n", i, x)
case nil:
fmt.Printf("param #%d is a nil\n", i)
case string:
fmt.Printf("param #%d is a string, value: %s\n", i, x)
default:
fmt.Printf("param #%d's type is unknow\n", i)
}
}
}

函数

匿名函数

未指明函数名的函数,用处:

直接赋值给函数变量

sumFun := func(num1, num2 int) int {
return num1 + num2
}
sum := sumFun(10, 20)

直接执行

func(name string) {
fmt.Println("Hello", name)
}("TOMOCAT")

作为回调函数 作为参数传入函数实现不同功能

package main

import (
"fmt"
)

/*
求和并调用callback函数对结果进行特殊处理
*/
func sumWorker(data []int, callback func(int)) {
sum := 0
for _, num := range data {
sum += num
}

callback(sum)
}

func main() {
// 打印出求和结果
sumWorker([]int{1, 2, 3, 4}, func(a int) {
fmt.Println("sum:", a)
})

// 判断求和结果是否大于100
sumWorker([]int{1, 2, 3, 4}, func(a int) {
if a > 100 {
fmt.Println("sum > 100")
} else {
fmt.Println("sum <= 100")
}
})
}

闭包

Golang中所有的匿名函数都是闭包。

闭包可以理解为一个函数“捕获”了和它处于同一作用域的其他变量

类型转换

需要注意数值之间进行转换可能造成其他问题,如精度丢失或者错误的结果

类型断言

interface{} 类型表示一个空接口,任何类型都满足空接口。即interface{} 类型的值可以用于表示任意 Go 语言类型的值。将interface{}类型转换为需要的类型时称为类型断言。使用方法:

var i interface{} = 99 // 创建一个interface{}类型,其值为99
j := i.(int) // 我们假设i是兼容int类型,并使用类型断言将其转换为int类型

错误处理

可以将error接口作为多返回值的最后一个

func foo(param int)(ret int, err error)
{
...
}
n, err := foo(0)
if err != nil {
// 错误处理
} else {
// 使用返回值n
}

面向对象编程

自定义类型

通过结构体定义类型

type ColorPoint struct {
color.Color // 匿名字段(嵌入)
x, y int // 具名字段(聚合)
}

初始化对象实例

a := new(ColorPoint)
a := &ColorPoint{}
a := &ColorPoint{"Pink",18}
a := &ColorPoint{color: "Pink",x: 18}