GoLang记录

goroute、select、channel练习

请写出一个场景:二营长的意大利炮

为了高效的打鬼子,二营长搬出了他珍藏的一门意大利炮,并命令一堆手下来操作意大利炮

  • 发射一下意大利炮需要经过三个步骤:装填瞄准发射
  • 每个阶段打印出这个阶段的名称即可
  • 每一个手下都是一个 goroutine
    • 每个手下只负责一个步骤
  • 需要使用 channel 来同步各个手下的操作
  • 作为指挥的二营长,他希望一个命令就可以停止打炮
    • 按下 q 就停止打炮了,kill 进程不算
    • 可以使用 "github.com/eiannone/keyboard" 来监听键盘按键事件
package main

import (
"fmt"
"github.com/eiannone/keyboard"
"time"
)

func main() {
var (
// 创建用于同步的通道
aim = make(chan struct{})
load = make(chan struct{})
launch = make(chan struct{})
stop = make(chan struct{})
)

go handleLoad(load, aim, stop)
go handleAim(aim, launch, stop)
go handleLaunch(launch, stop)

go listenQuit(stop)

// 空结构体通常用于在 goroutine 之间传递信号,适用于只需要信号不需要数据的场景
load <- struct{}{}

// 监听多个信道
select {
case <-launch:
fmt.Println("任务完成!")
case <-stop:
fmt.Println("停止打炮!")
}
}

func handleAim(load chan struct{}, aim chan struct{}, stop chan struct{}) {
select {
case <-load:
fmt.Println("正在瞄准!")
time.Sleep(5 * time.Second)
aim <- struct{}{}
case <-stop:
}
}

func handleLoad(aim chan struct{}, launch chan struct{}, stop chan struct{}) {
select {
case <-aim:
fmt.Println("正在装填!")
time.Sleep(10 * time.Second)
launch <- struct{}{}

case <-stop:
}
}

func handleLaunch(launch chan struct{}, stop chan struct{}) {
select {
case <-launch:
fmt.Println("发射!")
case <-stop:
}
}

func listenQuit(stop chan struct{}) {
defer keyboard.Close()
if err := keyboard.Open(); err != nil {
fmt.Println("Failed to open keyboard!", err)
return
}

for {
char, _, err := keyboard.GetSingleKey()
if err != nil {
fmt.Println("Failed to read keyboard input!")
continue
}
if char == 'q' || char == 'Q' {
close(stop)
break
}
}
}

结构体练习

package main

import "fmt"

type Movie struct {
Name string
Director string
Time string
Score float64
UserRate []float64
}

func (m *Movie) AddUserRate(rate float64) {
m.UserRate = append(m.UserRate, rate)
}

func main() {
a := Movie{Name: "西线无战事",
Director: "爱德华·贝尔格",
Time: "148 minutes",
Score: 8.8,
}
fmt.Printf("请输入你的命令:\n1.获得名字\n2.获得导演名\n3.获得片长\n4.获得评分\n5.用户评分\n6.退出程序\n")
var option int
for {
fmt.Scanf("%d ", &option)
switch option {
case 1:
fmt.Println(a.Name)
case 2:
fmt.Println(a.Director)
case 3:
fmt.Println(a.Time)
case 4:
if len(a.UserRate) == 0 {
fmt.Println("暂无评分!")
} else {
for i, rate := range a.UserRate {
fmt.Printf("用户 %d 评分: %.1f\n", i+1, rate)
}
}
case 5:
var rate float64
fmt.Println("请输入评分(0-10.0):")
fmt.Scanln(&rate)
if rate < 0 || rate > 10 {
fmt.Println("无效评分!请重新输入。")
} else {
a.AddUserRate(rate)
fmt.Println("评分已添加!")
}
case 6:
return
default:
fmt.Println("无效的选项,请重新输入。")
}
fmt.Printf("\n请输入你的命令:\n1.获得名字\n2.获得导演名\n3.获得片长\n4.获得评分\n5.用户评分\n6.退出程序\n")
}
}

database/mysql连接数据库

import (
"database/sql" //标准库
_ "github.com/go-sql-driver/mysql" //我们使用的mysql,需要导入相应驱动包,否则会报错
"log"
)

var db *sql.DB

func InitDB() {
var err error
// 设置一下dns charset:编码方式 parseTime:是否解析time类型 loc:时区
dsn := "root:123456@tcp(192.168.10.104:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"
// 打开mysql驱动
db, err = sql.Open("mysql", dsn)
if err != nil {
log.Fatalln(err)
}
// 尝试与数据库建立连接(校验dsn是否正确)
err = db.Ping()
if err != nil {
log.Fatalln(err)
}
log.Println("DB connect success")
return
}

目录规范

------------------------- go目录 ----------------------------
/cmd:项目的可执行文件名称相符,通常有一个简短的main函数。从/internal和/pkg目录导入代码。其他没有了
/internal: 私有应用程序和库代码
/pkg:外部应用可以导入的库代码
/vendor:应用程序依赖项
-----------------服务应用程序目录 ---------------
/api:协议文件
/web: 静态web组件
-----------------通用应用目录 ---------------
/configs:项目的默认配置
/init:system init (systemd,upstart,sysv) 配置
/scripts:执行各种构建、安装、分析等操作的脚本
/build:打包和持续集成
/deployments:部署配置
/test:测试
-----------------其他目录 ---------------
/docs:文档
/tools:项目支持的工具
/examples:应用程序和公共库实例
/third_party:外部工具
/githooks: -
/assets: 图片和其他存储的文件
/website:-
不应该有的目录
/src:请不要将项目级别的src目录和工作空间的src目录混淆。