go in action笔记

空白标识符 _

空白标识符作为import某个包的别名,适用场景为
1. 明确地希望适用某个包导入的副作用
2. 避免编译错误产生

package postgres

import(
    "database/sql"
)

func init() {
    sql.Register("Postgres", new(PostgresDriver))
}


package main

import (
    "database/sql"
    _ "postgres"
)

func main(){
    sql.Open("postgres", "mydb")
}

上面的代码中,我们希望用到postgres包中的init函数所产生的副作用将数据库驱动注册好,同时我们的main包中没有使用任何postgres包中的成员,为了避免编译器报错,我们用_作为别名

切片

索引切片

s := []string{99:""}

声明了一个切片,有100个元素。

空切片

var s1 []int
s2 := []int{}
s3 := make([]int, 0)

声明了一个切片长度为0,容量为0
nil切片在标准库中很常用。

长度与容量

slice[i:j:k]
长度: j - i
容量: k - i

【建议】将切片的长度和容量设置为相同大小。

func main() {
    var s []int
    fmt.Println(len(s))
    arr := [...]int{1, 2, 3, 4, 5}
    sli := arr[1:3]
    fmt.Println(sli)
    fmt.Println(arr)
    sli = append(sli, 9)
    fmt.Println(sli)
    fmt.Println(arr)
}

输出结果为

0
[2 3]
[1 2 3 4 5]
[2 3 9]
[1 2 3 9 5]
[2 3 10]
[1 2 3 9 5]

如果将长度和容量设为相同,可以避免很多隐晦的安全隐患。

类型和接口

类型与类型指针

package main

import (
    "fmt"
)

type user struct {
    name  string
    email string
}

func (u user) notify() {
    fmt.Println("sending to:", u.name, u.email)
}

func (u *user) changeEmail(email string) {
    u.email = email
}

func main() {
    bill := user{name: "bill",
        email: "[email protected]",
    }
    bill.notify()

    lisa := &user{"lisa", "[email protected]"}
    lisa.notify()  //Go在背后执行的动作:(*lisa).notify()

    bill.changeEmail("[email protected]")  //(&bill).changEmail(...)
    bill.notify()

    lisa.changeEmail("[email protected]")
    lisa.notify()

}

结果

sending to: bill bill@a.com
sending to: lisa lisa@a.com
sending to: bill [email protected]
sending to: lisa [email protected]

方法集规则

values methods receivers
T (t T)
*T (t T) and (t *T)

另一个角度:

methods receivers values
(t T) T and *T
(t *T) *T

如果定义方法时类型参数的形参使用指针,那么调用方发时只能传给它指针,如果定义方发时类型参数的形参使用类型的值,那么调用方发时可以传值也可以传指针。

package main

import (
    "fmt"
)

type notifier interface {
    notify()
    notify1()
}

type user struct {
    name  string
    email string
}

type admin struct {
    name  string
    email string
}

func (u *user) notify() {
    fmt.Println("By pointer:", u.name, u.email)
}

func (u user) notify1() {
    fmt.Println("By value:", u.name, u.email)
}

func main() {
    u := user{"Alice", "[email protected]"}
    up := &u
    u.notify()
    u.notify1()
    up.notify1()
    up.notify()
    sendNotification(up)
    //39:18: cannot use u (type user) as type notifier in 
    //argument to sendNotification: user does not implement 
    //notifier (notify method has pointer receiver)
    sendNotification(u) //编译错误
    //41:19: cannot use u (type user) as type *notifier in 
    //argument to sendNotification1:    *notifier is 
    //pointer to interface, not interface
    sendNotification1(u) //编译错误
    //43:19: cannot use up (type *user) as type *notifier 
    //in argument to sendNotification1: *notifier is 
    //pointer to interface, not interface
    sendNotification1(up) //编译错误
}

func sendNotification(n notifier) {
    n.notify()
}

//
func sendNotification1(n *notifier) {
    (*n).notify()
}

//57:3: n.notify undefined (type *notifier is pointer to 
    //interface, not interface)
func sendNotification2(n *notifier) {
    n.notify()
}

并发

continue / break / 标号

break 和 continue可以加标号,但二者跳转到某一个标号的后续操作不同。

扫描二维码关注公众号,回复: 2706093 查看本文章

race 选项

go build -race
go run -race test.go

竞争条件

原子函数

atomic.CompareAndSwapInt32(addr, old, new)
atomic.LoadInt32(addr){
atomic.StoreInt32(addr, val)
atomic.AddInt32(addr, delta)
atomic.SwapInt32(addr, new)

原子操作由底层硬件支持,效率要比mutex高

mutex

var mutex Sync.Mutex
mutex.Lock()
mutex.Unlock()

channel

读取一个channeldata, ok := <-c有三种情况
1. c未关闭、有数据, ok == true data有值
2. c未关闭、无数据, 当前goroutine阻塞
3. c已关闭, ok == false data == 0

pits

println vs fmt.Println

println 总是要比 fmt.Println 晚输出。没搞清楚原因,怀疑
1. 缓存区不同
2. 输出前者输出到stderr, 后者输出到stdout

log

package main

import (
    "io"
    "io/ioutil"
    "log"
    "os"
)

var (
    Trace   *log.Logger
    Info    *log.Logger
    Warning *log.Logger
    Error   *log.Logger
)

func init() {
    const logfile = "errors.txt"
    file, err := os.OpenFile(
        logfile,
        os.O_CREATE|os.O_WRONLY|os.O_APPEND,
        0666)
    if err != nil {
        log.Fatalln("Failed to open error log file:", err)
    }
    Trace = log.New(ioutil.Discard,
        "TRACE",
        log.Ldate|log.Ltime|log.Lshortfile)
    Info = log.New(os.Stdout,
        "INFO",
        log.Ldate|log.Ltime|log.Lshortfile)
    Warning = log.New(os.Stdout,
        "WARNING",
        log.Ldate|log.Ltime|log.Lshortfile)
    Error = log.New(io.MultiWriter(file, os.Stderr),
        "ERROR",
        log.Ldate|log.Ltime|log.Lshortfile)
}

func main() {
    Trace.Println("tracing")
    Info.Println("special infomation")
    Warning.Println("be attention please")
    Error.Println("something failed")
}

json

json.NewDecoder(resp.Body).Decode(&gr)
json.Unmarshal([]byte(JSON), &c) //c可以是类型,也可以是map
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

IO

UT

猜你喜欢

转载自blog.csdn.net/suanmeitang/article/details/81484378
今日推荐