Open better2021 opened 5 years ago
Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题
使用它后,不但代码量减少了很多,而且程序变得更优雅。在defer后指定的函数会在函数退出前调用。
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}
如果有很多调用defer,那么defer是采用后进先出模式,所以如下代码会输出4 3 2 1 0
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
点操作
import(
. "fmt"
)
这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用的fmt.Println("hello world")可以省略的写成Println("hello world")
别名操作
import(
f "fmt"
)
别名操作的话调用包函数时前缀变成了我们的前缀,即f.Println("hello world")
_操作 这个操作经常是让很多人费解的一个操作符,请看下面这个import
import (
"database/sql"
_ "github.com/ziutek/mymysql/godrv"
)
_操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。
#string到int
int,err:=strconv.Atoi(string)
#string到int64
int64, err := strconv.ParseInt(string, 10, 64)
#int到string
string:=strconv.Itoa(int)
#int64到string
string:=strconv.FormatInt(int64,10)
str2 := "hello"
data2 := []byte(str2)
fmt.Println(data2) // [104 101 108 108 111]
str3 := string(data2) // hello
fmt.Println(str3)
查询语句
db.Select("user_name").Find(&users) // 只查询数据中的user_name字段
db.Where("sex=?","boy").Find(&users) // 查询sex为boy的数据
db.Where("id > ?",3).Find(&users) // 查询id大于3的数据
db.Raw("select * from users").Scan(&users) // 原生的sql查询
db.First(&users) // 获取第一条数据
db.Last(&users) // 获取最后一条数据
// 根据名字模糊查询数据
db.Where("user_name LIKE ?","%" + name + "%").Find(&users).Count(&count)
新增语句
db.Create(data) // data := &model.User{}
修改语句
db.Model(data).Where("id=?",id).Update(data) // 根据id修改数据
删除语句
db.Where("id=?",id).Delete(model.User{})
primary key
主键约束
unique
唯一约束
not null
非空约束
auto_increment
自动增长
删除表 :drop table 表名 修改:
查询表结构:
表中的数据操作 插入 : insert into 表名(列名,列名) values(值1,值2) 删除 :delete from 表名 where 条件 修改 : update 表名 set 列名=“值”,列名=“值” where 条件 查询 :select [distinct] * [列名] from 表名 where 条件
聚合函数:sum(),avg(),count(),max(),min() 排序:order by (asc升序 ,desc 降序)
package main
import (
"database/sql"
"fmt"
//"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "astaxie:astaxie@/test?charset=utf8")
checkErr(err)
//插入数据
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
checkErr(err)
res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
fmt.Println(id)
//更新数据
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
checkErr(err)
res, err = stmt.Exec("astaxieupdate", id)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println(affect)
//查询数据
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username string
var department string
var created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println(uid)
fmt.Println(username)
fmt.Println(department)
fmt.Println(created)
}
//删除数据
stmt, err = db.Prepare("delete from userinfo where uid=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println(affect)
db.Close()
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
sql.Open()函数用来打开一个注册过的数据库驱动,go-sql-driver中注册了mysql这个数据库驱动,第二个参数是DSN(Data Source Name),它是go-sql-driver定义的一些数据库链接和配置信息。它支持如下格式:
user@unix(/path/to/socket)/dbname?charset=utf8
user:password@tcp(localhost:5555)/dbname?charset=utf8
user:password@/dbname
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname
我们可以看到我们传入的参数都是=?对应的数据,这样做的方式可以一定程度上防止SQL注入。
fileURL,_ := os.Getwd() // 获取到文件的相对路劲
path := strings.Replace(fileURL, "\\", "/", -1) // 替换\\为/
fmt.Println(path,"--")
d1 := []byte("hello\ngo\n")
errs := ioutil.WriteFile(path + "/lesson/file/aa.txt",d1,0644) // 0644 为读写权限
check(errs)
f,err:=os.Create(path + "/lesson/file/bb.txt")
check(err)
defer f.Close()
var wg sync.WaitGroup // 创建一个同步等待组的对象
func main(){
wg.Add(2) // 2个goroutine
go printNum()
go printStr()
fmt.Println("进入阻塞状态")
wg.Wait() // 表示goroutine进入等待,意味着阻塞
fmt.Println("解除阻塞")
}
func printNum() {
for i:=1;i<=1000;i++{
fmt.Println("打印数字",i)
}
wg.Done() // 给wg等待组中的counter数值减1,同 wg.Add(-1)
}
func printStr(){
defer wg.Done() // 使用defer写法更优雅
for i:=1;i<=1000;i++{
fmt.Println("字母",i)
}
}
xxx{变量}
中的{}里面可以写变量,跟js的es6的模板字符串有点类似var orderField = "created_at"
var orderASC = "DESC"
if c.Query("asc") == "1" {
orderASC = "ASC"
} else {
orderASC = "DESC"
}
cateIDStr := c.Query("cateId")
if cateIDStr == "" {
categoryID = 0
} else if categoryID, err = strconv.Atoi(cateIDStr); err != nil {
fmt.Println(err.Error())
SendErrJSON("分类ID不正确", c)
return
}
var sql = `SELECT distinct(articles.id), articles.name, articles.browse_count, articles.comment_count, articles.collect_count,
articles.status, articles.created_at, articles.updated_at, articles.user_id, articles.last_user_id
FROM articles, article_category
WHERE articles.id = article_category.article_id
{statusSQL}
AND article_category.category_id = {categoryID}
AND articles.deleted_at IS NULL
AND articles.id NOT IN ({topIDs})
{timeSQL}
ORDER BY {orderField} {orderASC}
LIMIT {offset}, {pageSize}`
go version
go env
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
str1 := "hello world"
str2 := "你好,"
fmt.Println(len(str1)) // 11
fmt.Println(len(str2)) // 9
fmt.Println(utf8.RuneCountInString(str2)) // 3
}
到底传指针有什么好处呢?
channel
,slice
,map
这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)