这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
基础语法
- go 应用程序的执行入口是
main()函数 - go 语言严格区分大小写
- go 方法由一条条语句语句构成,不用加
; - go 编译器是一行一行的编译的,我们一行就写一条语句,不能写多条在同一行
- go 语言定义变量或者
import的包,若未使用,编译不通过
变量
package main
import "fmt"
func main(){
//var 变量名 数据类型 = 值
var i int = 10
var j int
var k = 1.1
a := i
fmt.Println("i=",i,"\nj=",j,"\nk=",k,"\na=",a)
}
go 中变量三种使用方式:
- 指定变量类型,声明后若不赋值,使用默认值
- 根据值自行判断变量数据类型(类型推导)
- 省略 var ,注意
:=(两步定义加赋值)左侧的变量不应该是已经声明过的,否则会导致编译错误
一次性声明多个变量:
var n1, n2, n3, n4 int
var n5, name, n6 = 100, "tom", 12
n7, name1, n8 := 100, "tom", 12
循环
go 中只有 for 循环语句:
for {
...
}
for i := 0; i < n; i++ {
...
}
switch
switch后面跟随变量switch后面不跟随变量,在case处写条件
数组
- 在 go 中数组是值类型,在默认情况下是值传递,因此会进行值拷贝
- 一个数组申请后就是一个 slice 切片
- 长度是数组类型数据的一部分,在传递函数参数时,应考虑数组长度,不同长度数组是不同数据类型
package main
import "fmt"
func main(){
//1.定义一个数组, 默认值 全部的二进制0
var arr [2]int
//2.赋值
arr[0] := 1
arr[1] := 2
//3.遍历方式
//常规
for i := 0 ; i < len(arr); ++i{
fmt.Println(arr[i])
}
// for-range 结构遍历 类似 java增强for
/*
可以用 若不想接收index 可以用_ 占位符
for index, value := range array {
...
}
*/
for index, value := range arr{
fmt.Println("index = %v, value = %v", index, value)
}
var arr1 []int = [3]int{1, 2, 3 }
//类型推导
var arr2 = [3]int{1, 2, 3}
//...固定写法
var arr3 = [...]int{1, 2, 3}
//指定对应下标的值
var arr4 = [...]int{1: 100, 0: 200, 2: 200}
}
切片
- 切片是数组的一个引用,是引用类型,遵循引用传递机制
- 切片长度可变,是一个可以动态变化的数组,使用类似数组
- 定义的基本语法
var sliceName []type
package main
import "fmt"
func main(){
var arr = [...]int{0, 1, 2, 3, 4}
//切片使用方式
//1. 声明一个切片,然后让切片去引用一个创建好的数组
slice := arr[1:3]//表示引用arr 下标 [1,3) 的部分
//2.通过 make 来创建切片 var 切片名 []type = make([]type, len, [cap])
var slice1 []int = make([]int, 4, 10)
}
方式一和方式二的区别:
- 方式一是直接引用的数组,这个数组是事先创建的,程序员可见
- 方式二通过 make 来创建切片, make 也会创建一个数组,是由切片在底层维护的,程序员不可见
append:
//切片引用的简写 起始为 0,结尾为 len(arr) 时可省略(这两值为默认值)
var slice = arr[0:len(arr)]
=> var slice = arr[:len(arr)]
=> var slice = arr[0:]
=> var slice = arr[:]
//切片可以继续切片
slice1 := slice[1:3]
//对切片的动态追加 append
var slice2 []int = []int{1, 2, 3}
slice2 = append(slice2, 4, 5)
//通过append 追加一个切片
slice1 = append(slice1, slice2...)
append 底层原理:
- 本质是对数组的扩容
- go 底层会创建一个新的数组(扩容后大小)
- 将原 slice 的元素拷贝到新数组中
- slice 重新引用到新的数组
copy:
//切片使用 copy 内置函数完成拷贝
var slice []int = []int{1,2,3}
var slice1 []int = make([]int, 10)
copy(slice1, slice)
- copy 要求的两个参数必须都是切片 copy(dest, src)
- 以上代码
copy后 slice 和 slice1 的数据空间是独立的
map
map的声明:var mapName map[keyType]valueType
初始化:需要make分配内存
func main(){
//方式一 声明,make
var myMap map[string]string
myMap = make(map[string]string)
myMap["a"] = "b"
myMap["c"] = "d"
//方式二 声明直接make
var myMap1 = make(map[string]string)
//方式三 声明make直接赋值
myMap2 := make(map[string]string{
"a" : "b",
})
//map 的增加和更新 map[key] = value
//若key 不存在则增加,已经存在则更新 value
myMap["a"] = "c"
//删除 delete(mapName, key), go中没有方法一次删除所有key,需遍历删除
delete(myMap, "a")
//查找 返回两个值 value,tag tag表示 key 是否存在于 map 中
val, tag := myMap["a"]
//map 的遍历 只能使用 for-range 结构遍历
for key, value := range mayMap{
fmt.Println("key = %v, value = %v", key, value)
}
//len 也可以获得 map 的大小
fmt.Println("myMap length = %v", len(myMap))
}
结构体
结构体是值类型
- 结构体的所有字段在内存中是连续分布的
- 结构体是用户单独定义的类型,和其他类型进行转换时需要完全相同的字段(成员名,个数,类型)
- 结构体进行 type 重新定义(相当于取别名),golang 认为是新的数据类型,但是可以相互间强转
- struct 的每个字段上,可以写上一个 tag,该 tag 可以通过反射机制获取,常见的使用场景就是序列化和反序列化
package main
import (
"fmt"
"encoding/json"
)
type Person struct{
Name string `json:"name"`//`json:"name"`就是一个结构体 tag, 当被 json 包内方法调用时候,Name 会被替换为我们设定的 tag name
Age int `json:"age"`
}
func main(){
person := Person{"mark", 10}
//将 person 序列化为 json 格式字串
// json.Marshal() 序列化
//json.Unmarshal() 反序列化
jsonStr, err := json.Marshal(person)
if err != nil {
fmt.Println("json 错误", err)
}
fmt.Println("jsonStr",string(jsonStr))
}