map1 := make(map[string]string, 5)
map2 := make(map[string]string)
map3 := map[string]string{
}
map4 := map[string]string{
"a": "1", "b": "2", "c": "3"}
上图的四个方法是新增一个字典的方法,key值包含在【】中后面的是value
for key,value:=range map1{
fmt.Printf("key=%d",key)
fmt.Printf("value=%s\n",value)
}
value,exist:=map["test"]//判断“test”键是否存在,value为test对应的数值
func main() {
i := 0
str := "mike"
//方式1
f1 := func() {
//匿名函数,无参无返回值
//引用到函数外的变量
fmt.Printf("方式1:i = %d, str = %s\n", i, str)
}
f1() //函数调用
//方式1的另一种方式
type FuncType func() //声明函数类型, 无参无返回值
var f2 FuncType = f1
f2() //函数调用
//方式2
var f3 FuncType = func() {
fmt.Printf("方式2:i = %d, str = %s\n", i, str)
}
f3() //函数调用
//方式3
func() {
//匿名函数,无参无返回值
fmt.Printf("方式3:i = %d, str = %s\n", i, str)
}() //别忘了后面的(), ()的作用是,此处直接调用此匿名函数
//方式4, 匿名函数,有参有返回值
v := func(a, b int) (result int) {
result = a + b
return
}(1, 1) //别忘了后面的(1, 1), (1, 1)的作用是,此处直接调用此匿名函数, 并传参
fmt.Println("v = ", v)
}
————————————————
版权声明:本文为CSDN博主「Mike江」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tennysonsky/article/details/78147905
错误处理
最基础的错误处理是抛出err todo
随机数生成
背下代码就行异曲同工,使用时间种子定义确保生成的不同
import (
"fmt"
"math/rand"
"time"
)
func main() {
var arr [5]int
rand.Seed(time.Now().Unix()) //产生Seed
rand.Seed(time.Now().UnixNano())//两种方法都可以
for i:= 0;i<len(arr) ;i++ {
arr[i] = rand.Intn(100) //生成[0,100)的随机数
}
fmt.Println(arr)
}
context.Context
是一个接口,该接口定义了四个需要实现的方法。具体签名如下:type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{
}
Err() error
Value(key interface{
}) interface{
}
}
Go语言中提供的原子操作都是非侵入式的,在标准库代码包sync/atomic中提供了相关的原子函数。
func main() {
var counter int64 = 23
atomic.AddInt64(&counter,-3)
fmt.Println(counter)
}
---output---
20
一些基础的操作。比如Store,Load,操作如下,需先定义atomic.Value变量名
func main() {
var Atomicvalue atomic.Value
Atomicvalue.Store([]int{
1,2,3,4,5})
anotherStore(Atomicvalue)
fmt.Println("main: ",Atomicvalue)
}
func anotherStore(Atomicvalue atomic.Value) {
Atomicvalue.Store([]int{
6,7,8,9,10})
fmt.Println("anotherStore: ",Atomicvalue)
}
---output---
anotherStore: {
[6 7 8 9 10]}
main: {
[1 2 3 4 5]}
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"os"
)
var db *sql.DB
type info struct {
//注意大写
Id int `db:"id"`
Name string `db:"name"`
}
func initDB()error{
var err error
db, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/learn_mysql?charset=utf8");
//上面的语句代表了连接的几点,首先mysql:数据库驱动;其次root:用户名;123456:密码;learn_mysql:库名
if err!=nil{
return err
}
err=db.Ping()
fmt.Println("connect success")
if err!=nil{
return err
}
db.SetMaxOpenConns(10)//设置最大的连接池中的数
return err
}
func insertDB(name string){
sqlStr:=`insert into class(name) values (?)`
ret,err:=db.Exec(sqlStr,name)
if err!=nil{
fmt.Println("insert err: ",err)
return
}
id,err:=ret.LastInsertId()//插入的位置
effectRow,err:=ret.RowsAffected()//影响的行数
if err!=nil{
fmt.Println("insert err: ",err)
return
}
fmt.Printf("insert in id:%d,effect row:%d\n",id,effectRow)
}
func updateDB(name string,id int){
sqlStr:=`update class set name=? where id =?`
ret,err:=db.Exec(sqlStr,name,id)//多个参数的输入,?为占位符
if err!=nil{
fmt.Println("update err: ",err)
return
}
ids,err:=ret.LastInsertId()
effectRow,err:=ret.RowsAffected()
if err!=nil{
fmt.Println("update err: ",err)
return
}
fmt.Printf("update in id:%d,effect row:%d\n",ids,effectRow)
}
func deleteDB(name string){
sqlStr:=`delete from class where name=?`
ret,err:=db.Exec(sqlStr,name)//多个参数的输入,?为占位符
if err!=nil{
fmt.Println("delete err: ",err)
return
}
ids,err:=ret.LastInsertId()
effectRow,err:=ret.RowsAffected()
if err!=nil{
fmt.Println("delete err: ",err)
return
}
fmt.Printf("delete in id:%d,effect row:%d\n",ids,effectRow)
}
func queryOneRowDB (id int){
sqlColm:=`select * from class where id=?`
var a info
err:=db.QueryRow(sqlColm,id).Scan(&a.Id,&a.Name)
if err!=nil{
fmt.Println("query err: ",err)
}
fmt.Println("one :",a)
}
func queryMoreRowDB (id int){
sqlColm:=`select * from class where id>?`
rows,err:=db.Query(sqlColm,id)
if err!=nil{
fmt.Println("query more err: ",err)
}
defer func(){
//一定要记得关闭
err:=rows.Close()
if err!=nil{
fmt.Println("close err: ",err)
}
}()
for rows.Next(){
//能够取值就读取下一行
var s info
err=rows.Scan(&s.Id,&s.Name)
fmt.Println("more: ",s)
}
}
func prepareDB (){
sqlStr:=`insert into class(name) values (?)`
stm,err:=db.Prepare(sqlStr)
if err!=nil{
fmt.Println("prepare insert err: ",err)
return
}
defer func() {
err:=stm.Close()
if err!=nil{
fmt.Println("close err: ",err)
}
}()
namelist:=[]string{
"xyp","xy","szp","dzx"}
for _,value:=range namelist{
_,err:=stm.Exec(value)
if err!=nil{
fmt.Println("prepare insert err: ",err)
return
}
}
}
func transactionDemo() {
tx, err := db.Begin() // 开启事务
if err != nil {
if tx != nil {
tx.Rollback() // 回滚
}
fmt.Printf("begin trans failed, err:%v\n", err)
return
}
sqlStr1 := "insert into class(name) values (?)"
_, err = tx.Exec(sqlStr1, "xixixi")
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql1 failed, err:%v\n", err)
return
}
_, err = tx.Exec(sqlStr1, "xixixi2")
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql1 failed, err:%v\n", err)
return
}
err = tx.Commit() // 提交事务
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("commit failed, err:%v\n", err)
return
}
fmt.Println("exec trans success!")
}
func main() {
err:=initDB()//自定义初始化数据库函数
if err!=nil{
fmt.Println("init error: ",err)
os.Exit(-1)//直接退出
}
queryOneRowDB(3 )//获取单行
queryMoreRowDB(0)//获取多行
insertDB("xy")//插入
updateDB("li",5)//更新
deleteDB("szp")//删除
prepareDB()//预操作,实现多个语句同时插入
transactionDemo()//对于一个事物的操作,分为begin,commit,rollback
}
学习过程:https://blog.csdn.net/qq_36431213/article/details/82967982
通过&【参数】来获取参数的地址
通过*【参数】来打印出指针变量的具体数值
如果不想通过下图的方法分配地址需要通过【指针类型参数】=new(int) 这种方式来分配地址
一段最简单的并发goroutine线程
func testRoutine (i int){
fmt.Println("输出",i)
}
func main() {
for i:=0;i<100;i++{
//开启一百个goroutine线程
go testRoutine(i)
}
time.Sleep(time.Second*1)
fmt.Println("main")
}
注意此处画圈的地方,为什么会出现此情况呢,因为启动goroutine需要时间,但f主线程的for循环不会等待goroutine线程启动,i会持续递增,当goroutine启动起来后才会再在外部取值,导致取得多次相同的i
func wgRoutine(i int){
defer wg.Done()//退出时执行done,进行计数器减一
fmt.Println("test",i)
}
var wg sync.WaitGroup//初始化计数器,全局变量
func main() {
for i:=0;i<100;i++{
//开启一百个goroutine线程
wg.Add(1)//计数器加一
go wgRoutine(i)
}
wg.Wait()//等待计数器减为零
fmt.Println("main")
var testChannel chan int //定义一个int类型的channel
testChannel=make(chan int)//初始化一个地址
学习过程:https://www.jianshu.com/p/24ede9e90490
channel的定义:channel 提供了一种通信机制,通过它,一个 goroutine 可以想另一 goroutine 发送消息。channel 本身还需关联了一个类型,也就是 channel 可以发送数据的类型。例如: 发送 int 类型消息的 channel 写作 chan int 。
通道是一个指针
ch<-10 //箭头代表数据流动的方向10流到了ch
x:=<-ch1 //将通道中的值赋给x
<-ch1 //不保存通道中的数值直接将数值扔掉
close(ch1)
ch := make(chan int, 10)
ch <- 11
ch <- 12
close(ch)//关闭后仍可以读取数据
for x := range ch {
//遍历
fmt.Println(x)
}
x, ok := <- ch//判断是否通道是否开启
fmt.Println(x, ok)
-----
output:
11
12
0 false
通道的类型有两种:不带缓存的 channel 和带缓存的 channel
testChannel=make(chan int)
wg.Add(1)
go func() {
defer wg.Done()
a:=<-testChannel
fmt.Println("a is ",a)
}()
testChannel<-3//如果不往通道中写入则在上方goroutine线程则会一直等待输入
wg.Wait()
ch := make(chan int, 10)
有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息。
单向通道
chan<- int 表示一个只可写入的 channel,<-chan int 表示一个只可读取的 channel。上面这个函数约定了 foo 内只能从向 ch 中写入数据,返回只一个只能读取的 channel,虽然使用普通的 channel 也没有问题,但这样在方法声明时约定可以防止 channel 被滥用,这种预防机制发生再编译期间。
select语句
每次选择一个能走通的case,全部走不通再走default
- select 可以同时监听多个 channel 的写入或读取
- 执行 select 时,若只有一个 case 通过(不阻塞),则执行这个case 块
- 若有多个 case 通过,则随机挑选一个 case 执行
- 若所有 case 均阻塞,且定义了 default 模块,则执行default 模块。
- 若未定义 default 模块,则 select 语句阻塞,直到有 case 被唤醒。
- 使用 break 会跳出 select 块。
ch3:=make(chan int ,1)
for i:=0;i<10;i++{
select {
case ch3<-i:
println("put ",i)
case x:=<-ch3:
println("selct",x)
default:
println("test")
}
}
----------output----------
put 0
selct 0
put 2
selct 2
put 4
selct 4
put 6
selct 6
put 8
selct 8
学习过程:https://www.liwenzhou.com/
学习视频:https://space.bilibili.com/4638193/video
创建项目时选择gomoudle,可以选择代理https://goproxy.cn
——————————————分割线———————————————
go自带的http包是net/http
使用net/http创建的一个很简单的网站,可以写一些html在上面
这是最开始的时候没有进行前后端分离的样子
——————————分割线————————————
gin中文文档:https://gin-gonic.com/zh-cn/docs/
Restful风格api:http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html
很基础的一个返回json串的后端编写//一般使用postman进行测试,因为浏览器不支持put,delete的请求
landeng(滑稽)
正在学习gorpc https://github.com/lubanproj/gorpc,走过路过点个红心,目前是contributor