1 ctrl+shift+d 调试
2 ctrl+shift+x 管理扩展
3 设置自动补全
go env -w GOPROXY=https://goproxy.cn,direct
Windows平台按下Ctrl+Shift+P
,Mac平台按Command+Shift+P
,这个时候VS Code界面会弹出一个输入框,如下图:>go:install Go:Install/Update Tools
设置自动保存
文件 首选项 设置 afterdelay
4 查看错误和警告 ctrl+shift+M
5切换集成终端 ctrl+·
setting.json
“go.useCodeSnippetsOnFunctionSuggest”: true
6正上方会出现一个框 Ctrl+Shift+P 弹出命令行
如果你的Windows
使用的是cmd
,那么按如下方式指定环境变量。
SET CGO_ENABLED=0 // 禁用CGO
SET GOOS=linux // 目标平台是linux
SET GOARCH=amd64 // 目标处理器架构是amd64
如果你的Windows
使用的是PowerShell
终端,那么设置环境变量的语法为
$ENV:CGO_ENABLED=0
$ENV:GOOS="linux"
$ENV:GOARCH="amd64"
7Linux编译Mac可执行文件
Linux平台下编译Mac平台64位可执行程序:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
Linux编译Windows可执行文件
Linux平台下编译Windows平台64位可执行程序:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
变量和常量
变量
变量的定义
var a int
var b bool
var c int8
var (
m int
n string
)
var name string = "nazha"
func main(){
age := 18//声明变量age同时初始化;编译器会根据右边的初始值推断出age是什么类型
}
常量
const PI = 3.1415926
const KB = 1024
iota
Go中借助iota来实现枚举
const (
n1 = iota //0
n2 //1
n3 //2
n4 //3
)
String
使用双引号表示字符串
“hello”
使用单引号表示字符
‘h’
字符串的常用方法
整型
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64
int是特殊的,会根据你的操作系统的位数来决定是int32还是int64
浮点型
float32 flot64
浮点数永远都是不精确.(为什么计算机表示的浮点数不精确)
-
转换成字符串去做运算
-
整体放大多少倍转换成整数进行运算
复数
complex64和complex128
布尔
var a bool//默认是false
var b = true
Go语言中布尔类型不能和其他类型做类型转换
byte和rune
英文字符用byte(ASCII码能表示的) 01010101
rune(中文,UTF8编码) 01010101 01010101 01010101
什么时候用rune?
s := "hello中国"
for i:=0;i<len(s);i++{
fmt.
}
详见课上代码.
流程控制
if
age := 20
if age>18{
}else if 20 > 18 {
}else{
}
//此时age只在if语句中有效
if age:=20;age>18{
}
for
//标准for循环
for i:=0;i<10;i++{
}
//类似while循环
n := 10
for n>0 {
fmt.Println(n)
n--
}
//无限循环
for {
}
switch和case
n := 10
switch n{
case 1:
...
case 2:
...
}
switch {
case n>0:
...
case n ==0:
...
}
为了兼容之前的C代码 fallthrough
以下是了解为主
goto+label
continue+label
break +label
作业
运算符
课后练习
把字符串的IP地址"192.168.19.200"转换成整数
格式化打印的参数
fmt.Println()
fmt.Printf("%s")
数组
数组是同一种数据类型元素的集合。
声明定义
初始化
二维数组
数组的遍历
数组是值类型
午后小分享
当你觉着不行的时候,你就去人行道上走一走,这个时候你就是一个行人。
切片
切片三要素:
- 地址(切片中第一个元素指向的内存空间)
- 大小(切片中目前元素的个数)
len()
- 容量(底层数组最大能存放的元素的个数)
cap()
切片支持自动扩容,扩容策略3种
-
每次只追加一个元素,每一次都是上一次的2倍
-
追加的超过原来容量的1倍,就等于原来的容量+扩容元素个数的最接近的偶数
-
如果切片的容量大于了1024,后续就每次扩容0.25倍 ?
给切片追加元素
append()
函数是往切片中追加元素的。
a = append(a, 1)
得到切片的三种方式:
- 直接声明
a := []int{1,2,3}
len:3 cap:3 - 基于数组得到切片
m := [5]int b:= m[:3]
len:3, cap:5 - 基于切片得到切片
b := a[:2]
len:2 cap:3
使用make初始化切片
make用于给引用类型申请内存空间
切片必须初始化,或者用append才能使用
var s []int
s = make([]int, 大小, 容量)
对切片初始化时,容量尽量大一点,减少程序运行期间再去动态扩容。
map
map定义
映射
, key-value结构
var n map[string]int
map初始化
make(map[string]int, [容量])
map的遍历
for … range 循环
可变参数
func add4(a int, b ...int) int {
}
可变参数只能有一个并且只能放在参数的最后!!!
Go语言中没有默认参数!!!
多返回值
func add5() (int, int, int) {
return 1, 2, 3
}
变量和常量
变量
变量的定义
var a int
var b bool
var c int8
var (
m int
n string
)
var name string = "nazha"
func main(){
age := 18//声明变量age同时初始化;编译器会根据右边的初始值推断出age是什么类型
}
常量
const PI = 3.1415926
const KB = 1024
iota
Go中借助iota来实现枚举
const (
n1 = iota //0
n2 //1
n3 //2
n4 //3
)
String
使用双引号表示字符串
“hello”
使用单引号表示字符
‘h’
字符串的常用方法
整型
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64
int是特殊的,会根据你的操作系统的位数来决定是int32还是int64
浮点型
float32 flot64
浮点数永远都是不精确.(为什么计算机表示的浮点数不精确)
-
转换成字符串去做运算
-
整体放大多少倍转换成整数进行运算
复数
complex64和complex128
布尔
var a bool//默认是false
var b = true
Go语言中布尔类型不能和其他类型做类型转换
byte和rune
英文字符用byte(ASCII码能表示的) 01010101
rune(中文,UTF8编码) 01010101 01010101 01010101
什么时候用rune?
s := "hello中国"
for i:=0;i<len(s);i++{
fmt.
}
详见课上代码.
流程控制
if
age := 20
if age>18{
}else if 20 > 18 {
}else{
}
//此时age只在if语句中有效
if age:=20;age>18{
}
for
//标准for循环
for i:=0;i<10;i++{
}
//类似while循环
n := 10
for n>0 {
fmt.Println(n)
n--
}
//无限循环
for {
}
switch和case
n := 10
switch n{
case 1:
...
case 2:
...
}
switch {
case n>0:
...
case n ==0:
...
}
为了兼容之前的C代码 fallthrough
以下是了解为主
goto+label
continue+label
break +label
#################################################################
数组的定义
数组是带长度和元素类型!!!
var a [3]int
var b [3]string
var c [5]int
数组的初始化
var a = [3]int{
1,2,3}
var b = [...]bool{
true, false}
var c = [5]string{
1:"娜扎", 3:"小王子"}
多维数组
var a = [3][2]int{
{
1, 2},
{
3, 4},
{
5, 6},
}
数组的遍历
- 根据索引index遍历
- for range遍历
切片
切片的定义
切片与数组的区别是没有固定的长度。
切片本质上就是一个数组。是语言层面对数组的封装。
切片是引用类型。
var a []int
var b []string
var c []bool
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xq27Jy9e-1678694805387)(D:\Go\src\code.oldboy.com\studygolang\day03\assets\1555208079167.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtDnfXba-1678694805388)(D:\Go\src\code.oldboy.com\studygolang\day03\assets\1555208177025.png)]
Go语言中类型的初始值
值类型
var a int//0
var b string//
var c float32//0
var d [3]int//[0 0 0]
var e bool//false
引用类型 make()是给引用类型申请内存空间
var x []int//nil
切片的初始化
- 声明变量时初始化
- 数组切片得到
- 切片再切片得到
- make()函数创建
切片追加元素 append()
必须用变量接收append
函数的返回值
切片的复制
copy(目标切片, 原切片)
切片删除元素
a = append(a[:1], a[2:]...)
map
map的定义
map是引用类型, 默认值是nil
map专门用来存储键值对类型的数据
判断某个键是否存在
v, ok := m[key]
函数
函数的定义
函数的参数
不带参数
多个相同类型的参数可以省略前面参数的类型
可变参数(...
)
func f1(){
fmt.Println("hello 沙河!")
}
//参数类型简写
func f2(name1, name2 string){
fmt.Println(name1)
fmt.Println(name2)
}
//可变参数 0个或多个
func f3(names ...string){
fmt.Println(names)//[]string
}
函数的返回值
不带返回值
单个返回值
多个返回值
命名返回值
func f4(){
fmt.Println("MJJ真烦")
}
func f5(a, b int) int{
return a+b
}
//多返回值,必须用括号括起来,用英文逗号分隔
func f6(a, b int) (int, int){
return a+b, a-b
}
//命名的返回值
func f6(a, b int) (sum int, sub int){
sum = a + b
sub = a - b
return
}
匿名函数和闭包
变量的作用域
1. 全局作用域
2. 函数作用域
3. 语句块作用域
defer
defer延迟执行函数
defer先注册后执行(在函数即将要结束但还没有结束的时候执行)
多用来做一些资源回收类的工作。
指针
指针和地址有什么区别?
地址:就是内存地址(用字节来描述的内存地址)
指针:指针是带类型的。
&
和*
&
:表示取地址
*
:根据地址取值
new和make
new:是用来初始化值类型指针的
make:是用来初始化slice
、map
、 chan
// 以下是错误的写法
// var a *int //a是一个int类型的指针
// var b *string
// var c *[3]int
// 以上是错误的写法
var a = new(int) //得到一个int类型的指针
fmt.Println(a)
*a = 10
fmt.Println(a)
fmt.Println(*a)
var c = new([3]int)
fmt.Println(c)
c[0] = 1
fmt.Println(*c)
panic和recover
panic:运行时异常
recover:用来将函数在panic时恢复回来,用于做一些资源回收的操作
**注意:**程序会出现panic一定是不正常的。
结构体(struct)和方法
type
关键字用来在Go语言中定义新的类型。
自定义类型和类型别名
自定义类型
创造一个新类型
type NewInt int
类型别名(软链)
var MyInt = int
byte
: uint8 和 rune
:int32是Go语言内置的别名。
类型别名只在代码编写过程中生效,编译完不存在。
结构体的定义
//结构体
// 创在新的类型要使用type关键字
type student struct {
name string
age int
gender string
hobby []string
}
func main() {
var haojie = student{
name: "豪杰",
age: 19,
gender: "男",
hobby: []string{
"篮球", "足球", "双色球"},
}
//结构体支持.访问属性
fmt.Println(haojie)
fmt.Println(haojie.name)
fmt.Println(haojie.age)
fmt.Println(haojie.gender)
fmt.Println(haojie.hobby)
}
结构体的实例化
-
基本实例化
var haojie = student{ name: "豪杰", age: 19, gender: "男", hobby: []string{ "篮球", "足球", "双色球"}, }
结构体的初始化
结构体的内存布局
了解为主
结构体的字段在内存上是连续的。
func main() {
type test struct {
a int16
b int16
c int16
}
var t = test{
a: 1,
b: 2,
c: 3,
}
fmt.Println(&(t.a))
fmt.Println(&(t.b))
fmt.Println(&(t.c))
}
构造函数
func newStudent(n string, age int, g string, h []string) *student {
return &student{
name: n,
age: age,
gender: g,
hobby: h,
}
基于函数版学员信息管理系统
获取终端输入
需求分析
// 使用函数实现一个简单的图书管理系统。
// 每本书有书名、作者、价格、上架信息,
// 用户可以在控制台添加书籍、修改书籍信息、打印所有的书籍列表。
// 0. 定义结构体
// 1. 打印菜单
// 2. 等待用户输入菜单选项
// 3. 添加书籍的函数
// 4. 修改书籍的函数
// 5. 展示书籍的函数
// 6. 退出 os.Exit(0)
接口
接口的定义
接口是一种类型,是一种抽象的类型。
是一个规范一个约定一堆方法签名的集合。
type mover interface {
move()
}
实现接口
实现了改接口规定的所有方法就实现了该接口
空接口
interface{
}
任意变量都可以存到空接口变量中
指针接收者和值接收者实现接口的区别
文件操作
打开文件
os.Open()
os.OpenFile()
time包
格式化的时间:2006-01-02 15:04:05.000
##############################################################
并发
并发和并行的区别
并发:同一时间段同时在做多个事情
并行:同一时刻同时在做多个事情
进程、线程、协程
进程:一个程序启动之后就创建了一个进程
线程:操作系统调度的最小单位
协程:用户态的线程(Python\PHP)
goroutine第六天
go运行时 runtime(Go语言作者帮我做的一些事情)
一个goroutine对应一个任务(函数)。
启动goroutine使用go
关键字
sync.WaitGroup
Add(i)
:计数器+i
Done()
:计数器-1,最好用defer注册
Wait()
:等待
goroutine什么时候结束
一个goroutine对应一个任务(函数)。
函数结束了(return)goroutine就结束了
goroutine和线程的区别
m:n
将m个goroutine调度到n个线程上执行。
GOMAXPROCS
runtime.GOMAXPROCS(n)
channel
通道是引用类型,必须初始化才能使用。
ch1 := make(chan int, 10)
通道的基本操作
发送
接收
关闭
关闭的通道有哪些特点:
无缓冲通道和缓冲通道
无缓冲的通道:4*100交接棒,又称为同步通道
有缓冲的通道:可以让程序实现异步操作
取值时判断通道关闭
方法一: ok判断
// 利用for循环去通道ch1中接收值
for {
ret, ok := <-ch1 // 使用 value, ok := <-ch1 取值方式,当通道关闭的时候 ok = false
if !ok {
break
}
fmt.Println(ret)
}
方法二: for range 循环
// 利用for range 循环去通道ch1中接收值
for ret := range ch1 {
fmt.Println(ret)
}
随机数
math/rand
// 给rand加随机数种子实现每一次执行都能产生真正的随机数
rand.Seed(time.Now().UnixNano())
ret1 := rand.Int63() // int64正整数
fmt.Println(ret1)
ret2 := rand.Intn(101) // [1, 101)
fmt.Println(ret2)
select
select {
case ch1 <- 1:
...
case <- ch1:
...
case <- ch2:
...
}
单向通道
// chan *item :既能接收也能发送的一个队列
// chan<- *item :只能发送的一个队列(单向通道)
// <-chan *item :只能接收的一个队列(单向通道)
并发控制与锁
互斥锁
读写锁
只有在读的操作远远多于写的操作时使用读写锁才能提高性能。
sync.Once 和 sync.Map
########################################################