Go基础语法
切片和数组
数组(array)
- 数组是由若干相同类型元素组成的序列。
- 数组的长度是数组类型的一部分,一旦在声明中确定了数组类型的长度,就无法改变了;当需要规划程序所用的内存、避免内存二次分配操作时,使用数组类型。
- 数组类型的零值一定是一个不包含任何元素的空数组。
- 索引表达式会获得该数组值的一个元素,切片表达式则会得到一个元素类型与之相同的切片。
- 数组包含了数组长度、数组容量以及指向该数组的指针。
切片(slice)
- 切片可以看作一种对数组的包装形式,是针对其底层数组中某个连续片段的描述。
- 与数组不同,切片的类型字面量并不携带长度信息,切片的长度是可变的,且并不是类型的一部分。
- 切片值相当于对某个底层数组的引用,其内部结构包含了切片的长度、切片的容量和指向底层数组中某个元素的指针。
- 一个切片类型的零值总是nil,此零值的长度和容量都为0。
/* 切片
1: 占用资源很小
2: slice[a:b] 包含a索引值,不包含b索引值,默认容量上界索引为被操作对象容量上界索引
3: slice[a:b:c] 包含a索引值,不包含b索引值,容量上界索引为c
4: slice 只能向后扩展,不能向前扩展
5: slice append
(1)某次操作未超过该slice容量上界索引,此次改变会更新原数组;
(2)某次操作超过该slice容量上界索引则新的被操作对象数组会被新建,此次改变不会更新原数组
*/
nums := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s0 := nums[3:9] // 容量上界索引为10
s1 := nums[3:6:8] // 容量上界索引为8
s1 = append(s1, 100) // 此次,未超过该slice容量上界索引 更新原数组, 不新建数组
s1 = append(s1, 100, 100) // 此次,超过该slice容量上界索引 不更新原数组, 新建数组
字典(map)
java HashMap和go map的区别
Java 的HashMap 基于 Map 接口。 Java 中的HashMap 是由hash table + 链表/红黑树(链表长度大于8时扩展为红黑树),java 中的map同样仅使用一份代码,但要求map的key必须是Object的子类。 HashMap 和 Map 一样,键值对都是保存在一个内部类中的,而在 HashMap 类中有一个很重要的字段,那就是 Node[]table,即是一个哈希桶数组。Node 是 HashMap 的一个内部类,实现了 Map.Entry 接口,本质上就是一个映射 (键值对)。
static class <K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; //链表的下一个node
Node(int hash, K key, V value, Node<K,V> next) { ... }
/.../
}
go 中一个 map 就是一个哈希表的引用。用的是hash table + 链表实现的,使用链表来解决hash冲突问题,通过编译器配合runtime,所有的map 共用一份代码
结构体
结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合。每个数据称为结构体的成员。
// 结构体的定义
type Person struct{
id int
name string
}
// 构造函数
func newPerson(id int, name string) *person{
return &person{
id: id,
name: name,
}
}
方法和函数的区别在于:函数不属于任何类型,方法却属于特定的类型。
// 方法的声明
// 按照官方的推荐,接收者 p 应该是 类型的首字母小写
// 接收者类型,既可以是 指针,也可以是非指针类型
func (p person) try(name string) string {
fmt.Println(p.name, " --> ", name)
return name
}
json
结构体切片转JSON字符串,结构体中的成员首字母都需要大写:
type Person struct{
Id int
Name string
}
p1 := Person{1, "张三"}
p2 := Person{2, "李四"}
person := []Person{p1, p2}
bytes, _ := json.Marshal(person)
JSON字符串转切片:
// 定义结构体切片
var person []Person
// 将json字符串转成结构体切片
_ = json.Unmarshal([]byte(jsonStr), &person)
字符串操作
func Clone(s string) string: 复制字符串s,返回string
func Contains(s, substr string) bool: 判断s中是否包含子串substr
func Compare(a, b string) int: Compare返回一个整数,以字典方式比较两个字符串。如果a==b,结果将为0,如果a<b,则为-1,如果a>b,则结果为+1。
func Count(s, substr string) int: 在字符串s中字串substr的数量,返回整数。
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.Count("cheese", "e"))
fmt.Println(strings.Count("five", "")) // before & after each rune
}
func Index(s, substr string) int: 返回子串substr在字符串s中第一次出现的位置,若不存在则返回-1。
格式化输出
- v 值的默认格式。
- %+v 添加字段名(如结构体)
- %#v 相应值的Go语法表示
- %T 相应值的类型的Go语法表示
- %% 字面上的百分号,并非值的占位符 其中:
- 布尔值: %t true 或 false
- 整数值:
- %b 二进制表示
- %c 相应Unicode码点所表示的字符
- %d 十进制表示
- %o 八进制表示
- %q 单引号围绕的字符字面值,由Go语法安全地转义
- %x 十六进制表示,字母形式为小写 a-f
- %X 十六进制表示,字母形式为大写 A-F
- %U Unicode格式:U+1234,等同于 "U+%04X"
- 浮点数及复数:
- %b 无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat中的 'b' 转换格式一致。
- %e 科学计数法,例如 -1234.456e+78
- %E 科学计数法,例如 -1234.456E+78
- %f 有小数点而无指数,例如 123.456
- %g 根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出
- %G 根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出
- 字符串和Byte的切片表示:
- %s 字符串或切片的无解译字节
- %q 双引号围绕的字符串,由Go语法安全地转义
- %x 十六进制,小写字母,每字节两个字符
- %X 十六进制,大写字母,每字节两个字符
- 指针:
- %p 十六进制表示,前缀 0x
数字解析
- Atoi (string to int)
- Itoa (int to string)
i, err := strconv.Atoi("-42")
s := strconv.Itoa(-42)
错误处理
Go 的异常错误处理只有Error,任何错误都可以直接返回,而不是使用try catch进行,如果函数在运行中出现异常应该把异常返回,如果没有则返回nil,且每次调用可能出现异常的函数时应主动进行检查做出反应。
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。 error 类型是一个内置的接口类型,这是它在源码中的定义:
//error 接口内有一个返回字符串的方法Error()
type error interface {
Error() string
}
go对于错误提供了两种处理机制:
- 通过函数返回错误类型的值来处理错误。
- 通过panic打印程序调用栈,终止程序执行来处理错误。
所以对错误的处理也有两种方法,一种是通过返回一个错误类型值来处理错误,另一种是直接调用panic抛出错误,退出程序。 Go是静态强类型语言,程序的大部分错误是可以在编译器检测到的,但是有些错误行为需要在运行期才能检测出来。此种错误行为将导致程序异常退出。其表现出的行为就和直接调用panic一样:打印出函数调用栈信息,并且终止程序执行。