Tag - GoLang
前几天竟然被 switch/case 坑了一小下,坦白讲,能掉进这个坑,纯粹是基本语法不过关,把 Go 当成 C++ 了。
下面是一个简化后的粟子,通过一个人的名字来判断我认不认识他,最初写下这段代码的期望结果是:如果 name
是 John
或 Kenny
,把 i_knew_him
置为 true
,表示我认识这两个人,别人(默认)不认识。熟悉 C++ 的同学一定知道我为什么这样写。
var i_knew_him bool = false switch name { case "John": case "Kenny": i_knew_him = true }
但我们现在写的是 Go 语言,执行结果不一样了(敲黑板
我的好朋友 John
迎面走了过来,我却假装不认识他,i_knew_him = true
根本没有执行到,因为这条表达式只属于 case "Kenny"
……
正确的写法是什么样的呢?
case "John", "Kenny": i_knew_him = true
详见 Go 语言规范
<全文完>
今天花了 2.5 小时看完这本书,总体来说这本书的内容偏浅,拿来入门比较合适——当然对于我这种从不看书、只靠文档 + 实践学习语言的来说,一些基础的知识点还是有必要补补的。看书的过程简单记了下笔记,太基础的直接跳过了,只记了部分我认为比较关键的知识点。全书最核心的部分当数第四章——并发编程。
@author migege@github
@version 170622:1
func getName() (firstName, middleName, lastName, nickName string) {
firstName = "A"
middleName = "B"
lastName = "C"
nickName = "D"
return
}
f := func(x, y int) int {
return x + y
}
type Bird struct {
Name string
LifeExpectance int
}
func main() {
sparrow := &Bird{"Sparrow", 3}
s := reflect.ValueOf(sparrow).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
}
}
package main
/*
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import "unsafe"
func main() {
cstr := C.CString("Hello, world!")
C.puts(cstr)
C.free(unsafe.Pointer(cstr))
}
go run
go build
go test
gdb xxx
调试信息为 DWARFv3,>= gdb1.7
const (
c0 = iota
c1 = iota
c2 = iota
)
const (
Sunday = itoa
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays
)
cap()
和 len()
竟然支持 goto
defer func() {
if r := recover(); r != nil {
// do something
}
}
foo()
类型都是值传递
虚基类
type Job struct {
Command string
*log.Logger
}
func (job *Job) Start() {
job.Log("starting...")
}
一个类只需要实现了接口要求的所有函数,就认为这个类实现了该接口。
var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
}
switch v := arg.(type) {
case int:
case string:
default:
// ...
}
go 关键字
不要通过共享内存来通信,而应该通过通信来共享内存。
ch <- 1
channel 在被读取前,写入操作是阻塞的。
<- ch
channel 在被写入前,读取操作是阻塞的。
var ch chan int
var m map[string]chan bool
ch := make(chan int)
select {
case <- ch1:
case <- ch2:
default:
}
ch := make(chan int, 1024)
即使没有读取方,写入方也可以一直往 channel 里写入,在缓冲区被填满之前都不会阻塞。
timeout := make(chan bool, 1)
go func() {
time.Sleep(1e9)
timeout <- true
}
select {
case <- ch:
// ...
case <- timeout:
// timeout
}
可以用来实现 pipe。
var ch1 chan<- float64 // 仅写入
var ch2 <-chan int // 仅读取
close(ch)
x, ok := <-ch
runtime.GOMAXPROCS(runtime.NumCPU())
runtime.Gosched()
sync.Mutex
和 sync.RWMutex
var l sync.Mutex
func foo() {
l.Lock()
defer l.Unlock()
}
var once sync.Once
once.Do(...)
func CompareAndSwapUint64(val *unit64, old, new uint64) (swapped bool)
### HTTP 编程
```net/http
rpc.Register()
外网 IP 查询服务——这应该是我写过最简单、但又有实际用处的 TCP 服务了。
用 Go 语言实现,加上空行还不到 30 行代码,请自行前往 GitHub 获取。
通过 go build
命令编译,在 macOS 上编译 Linux 版本需要指定 GOOS
参数:
GOOS=linux go build main.go
生成的 main
可以直接运行了:
./main
或者更高级点,通过 supervisor
配置成服务,使用 supervisorctl
控制。
用 telnet
连接部署机器的 6666 端口即可,如 migege.com:6666:
telnet migege.com 6666 Trying 120.27.122.8... Connected to migege.com. Escape character is '^]'. 1xx.2xx.2xx.1xxConnection closed by foreign host.
再也不用担心 ns1.dnspod.net 没有响应了。