第1章 初识Go语言
1.1 语言简史
1.2 语言特性
1.2.1 自动垃圾回收
1.2.2 更丰富的内置类型
1.2.3 函数多返回值
1.2.4 错误处理
1.2.5 匿名函数和闭包
1.2.6 类型和接口
1.2.7 并发编程
package main import "fmt" func sum(values []int,resultChan chan int) { sum := 0 for _,value := range values { sum += value } resultChan <- sum } func main() { values := []int {1,2,3,4,5,6,7,8,9,10} resultChan := make(chan int,2) go sum(values[:len(values)/2],resultChan) go sum(values[len(values)/2:],resultChan) sum1,sum2 := <-resultChan,<-resultChan fmt.Println("Result:",sum1,sum2,sum1+sum2) }
1.2.8 反射
package main import ( "fmt" "reflect" ) type Bird struct { Name string LifeExpectance int } func (b *Bird) Fly() { fmt.Println("I am flying...") } 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()) } }
1.2.9 语言交互性
package main /* #include*/ import "C" import "unsafe" func main() { cstr := C.CString("Hello,World") C.puts(cstr) C.free(unsafe.Pointer(cstr)) }
1.3 第一个Go程序
package main import "fmt" func main() { fmt.Println("Hello,World") }
1.3.1 代码解读
1.3.2 编译环境准备
$go version
1.3.3 编译程序
1.4 开发工具选择
1.5 工程管理
package main import "os" import "fmt" import "simplemath" import "strconv" var Usage = func() { fmt.Println("USAGE: calc command [arguments] ...") fmt.Println("\nThe commands are:\n\tadd\tAddition of two values.\n\tsqrt\tSquare root of a non-negative value.") } func main() { args := os.Args if args == nil || len(args) < 2 { Usage() return } switch args[0] { case "add": if len(args) != 3 { fmt.Println("USAGE: cacl add") return } v1,err1 := strconv.Atoi(args[1]) v2,err2 := strconv.Atoi(args[2]) if err1 != nil || err2 != nil { fmt.Println("USAGE: calc add ") return } ret := simplemath.Add(v1,v2) fmt.Println("Result: ",ret) case "sqrt": if len(args) != 2 { fmt.Println("USAGE: calc sqrt ") return } v,err := strconv.Atoi(args[1]) if err != nil { fmt.Println("USAGE: calc sqrt ") return } ret := simplemath.Sqrt(v) fmt.Println("Result: ",ret) default: Usage() } }
package simplemath func Add(a int,b int) int { return a + b }
package simplemath import "testing" func TestAdd1(t *testing.T) { r := Add(1,2) if r != 3 { t.Errorf("Add(1,2) failed.Got %d,expected 3.",r) } }
package simplemath import "math" func Sqrt(i int) int { v := math.Sqrt(float64(i)) return int(v) }
package simplemath import "testing" func TestSqrt1(t *testing.T) { v := Sqrt(16) if v != 4 { t.Errorf("Sqrt(16) failed.Got %v,expected 4.",v) } }
1.6 问题追踪和调试
1.6.1 打印日志
1.6.2 GDB调试
1.7 如何寻求帮助
1.7.1 邮件列表
1.7.2 网站资源
1.8 小结
第2章 顺序编程
2.1 变量
2.1.1 变量声明
var v1 int var v2 string var v3 [10]int var v4 []int var v5 struct { f int } var v6 *int var v7 map[string]int var v8 func(a int) int var ( v1 int v2 string )
2.1.2 变量初始化
var v1 int = 10 var v2 = 10 v3 := 10
2.1.3 变量赋值
var v10 int v10 = 123 i,j = j,i
2.1.4 匿名变量
func GetName() (firstName,lastName,nickName string) { return "May","Chan","Chibi Maruko" } _,_,nickName := GetName()
2.2 常量
2.2.1 字面常量
2.2.2 常量定义
const Pi float64 = 3.14159265358979323846 const zero = 0.0 const ( size int64 = 1024 eof = -1 ) const u,v float32 = 0,3 const a,b,c = 3,4,"foo" const mask = 1 << 3
2.2.3 预定义常量
const ( c0 = iota c1 = iota c2 = iota ) const ( a = 1 << iota b = 1 << iota c = 1 << iota ) const ( u = iota * 42 v float64 = iota * 42 w = iota * 42 ) const x = iota const y = iota const ( c0 = iota c1 c2 ) const ( a = 1 << iota b c )
2.2.4 枚举
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday numberOfDays )
2.3 类型
布尔类型:bool 整型:int8,byte,int16,int,uint,uintptr等 浮点类型:float32,float64 复数类型:complex64,complex128 字符串:string 字符类型:rune 错误类型:error 指针(pointer) 数组(array) 切片(slice) 字典(map) 通道(chan) 结构体(struct) 接口(interface)
2.3.1 布尔类型
2.3.2 整型
2.3.3 浮点型
import "math" // p为用户定义的比较精度,比如0.00001 func IsEqual(f1,f2,p float64) bool { return math.Fdim(f1,f2) < p }
2.3.4 复数类型
2.3.5 字符串
package main import "fmt" func main() { str := "Hello, 世界" n := len(str) for i := 0; i < n; i++ { ch := str[i] fmt.Println(i,ch) } for i,ch := range str { fmt.Println(i,ch) } }
2.3.6 字符类型
2.3.7 数组
package main import "fmt" func Modify(array [5]int) { array[0] = 10 fmt.Println("In Modify(),array values:",array) } func main() { array := [5]int{1,2,3,4,5} Modify(array) fmt.Println("In main(),array values:",array) }
2.3.8 数组切片
package main import "fmt" func main() { var myArray [10]int = [10]int{1,2,3,4,5,6,7,8,9,10} var mySlice []int = myArray[:5] fmt.Println("Elements of myArray: ") for _,v := range myArray { fmt.Print(v," ") } fmt.Println("\nElements of mySlice: ") for _,v := range mySlice { fmt.Print(v," ") } fmt.Println() mySlice1 := make([]int,5) mySlice2 := make([]int,5,10) mySlice3 := []int{1,2,3,4,5} }
package main import "fmt" func main() { mySlice := make([]int,5,10) fmt.Println("len(mySlice):",len(mySlice)) fmt.Println("cap(mySlice):",cap(mySlice)) mySlice = append(mySlice,1,2,3) mySlice2 := []int{8,9,10} mySlice = append(mySLice,mySlice2...) }
2.3.9 map
package main import "fmt" type PersonInfo struct { ID string Name string Address string } func main() { var personDB map[string]PersonInfo personDB = make(map[string]PersonInfo) personDB["12345"] = PersonInfo{"12345","Tom","Room 203,..."} personDB["1"] = PersonInfo{"1","Jack","Room 101,..."} person,ok := personDB["1234"] if ok { fmt.Println("Found person",person.Name,"with ID 1234.") } else { fmt.Println("Did not find person with ID 1234.") } }
2.4 流程控制
2.4.1 条件语句
2.4.2 选择语句
switch i { case 0: fmt.Printf("0") case 1: fmt.Printf("1") case 2: fallthrough case 3: fmt.Printf("3") case 4,5,6: fmt.Printf("4,5,6"") default: fmt.Printf("Default") } switch { case 0 <= Num && Num <= 3: fmt.Printf("0-3") case 4 <= Num && Num <= 6: fmt.Printf("4-6") case 7 <= NUM && Num <= 9: fmt.Printf("7-9") }
2.4.3 循环语句
sum := 0 for i :=0; i < 10; i++ { sum += i } sum := 0 for { sum ++ if sum > 100 { break } } a := []int{1,2,3,4,5,6} for i,j := 0, len(a) - 1; i < j;i,j = i + 1, j - 1 { a[i],a[j] = a[j],a[i] } for j := 0; j < 5; j++ { for i := 0; i < 10; i++ { if i > 5 { break JLoop } fmt.Println(i) } } JLoop:
2.4.4 跳转语句
func myfunc() { i := 0 HERE: fmt.Println(i) i++ if i < 10 { goto HERE } }
2.5 函数
2.5.1 函数定义
2.5.2 函数调用
2.5.3 不定参数
package main import "fmt" func MyPrintf(args ...interface{}) { for _,arg := range args { switch arg.(type) { case int: fmt.Println(arg,"is an int value.") case string: fmt.Println(arg,"is a string value.") case int64: fmt.Println(arg,"is an int64 value.") default: fmt.Println(arg,"is an unknown type.") } } } func main() { var v1 int = 1 var v2 int64 = 234 var v3 string = "hello" var v4 float32 = 1.234 MyPrintf(v1,v2,v3,v4) }
2.5.4 多返回值
2.5.5 匿名函数与闭包
package main import "fmt" func main() { var j int = 5 a := func()(func()) { var i int = 10 return func() { fmt.Printf("i,j:%d,%d\n",i,j) } }() a() j *= 2 a() }
2.6 错误处理
2.6.1 error接口
2.6.2 defer
2.6.3 panic()和recover()
2.7 完整示例
2.7.1 程序结构
2.7.2 主程序
2.7.3 算法实现
2.7.4 主程序
2.7.5 构建与执行
2.8 小结
第3章 面向对象编程
3.1 类型系统
3.1.1 为类型添加方法
package main import "fmt" type Integer int func (a Integer) Less(b Integer) bool { return a < b } func (a *Integer) Add(b Integer) { *a += b } func (a Integer) Add1(b Integer) { a += b } func main() { var a Integer = 1 if a.Less(2) { fmt.Println(a,"Less 2") } a.Add(2) fmt.Println("a = ",a) a.Add1(2) fmt.Println("a = ",a) }
3.1.2 值语义和引用语义
3.1.3 结构体
3.2 初始化
3.3 匿名组合
3.4 可见性
3.5 接口
3.5.1 其他语言的接口
3.5.2 非侵入式接口
type File struct { } func (f *File) Read(buf []byte) (n int,err error) func (f *File) Write(buf []byte) (n int,err error) func (f *File) Seek(off int64,whence int) (pos int64,err error) func (f *File) Close() error type IFile interface { Read(buf []byte) (n int,err error) Write(buf []byte) (n int,err error) Seek(off int64,whence int) (pos int64,err error) Close() error } type IReader interface { Read(buf []byte) (n int,err error) } type IWriter interface { Write(buf []byte) (n int,err error) } type ICloser interface { Close() error } var file1 IFile = new(File) var file2 IReader = new(File) var file3 IWriter = new(File) var file4 ICloser = new(File)
3.5.3 接口赋值
package one type ReadWriter interface { Read(buf []byte) (n int,err error) Write(buf []byte) (n int,err error) } package two type IStream interface { Write(buf []byte) (n int,err error) Read(buf []byte) (n int,err error) } var file1 two.IStream = new (File) var file2 one.ReadWriter = file1 var file3 two.IStream = file2 type Writer interface { Write(buf []byte) (n int err error) } var file1 two.IStream = new(File) var file4 Writer = file1 var file1 Writer = new(File) var file5 two.IStream = file1 // 编译不能通过
3.5.4 接口查询
var file1 Writer = ... if file5,ok := file1.(two.IStream); ok { ... } var file1 Writer = ... if file6,ok := file1.(*File); ok { ... }
3.5.5 类型查询
3.5.6 接口组合
3.5.7 Any类型
3.6 完整示例
3.6.1 音乐库
3.6.2 音乐播放
3.6.3 主程序
3.6.4 构建运行
3.6.5 遗留问题
3.7 小结
第4章 并发编程
4.1 并发基础
4.2 协程
4.3 goroutine
package main import "fmt" func Add(x,y int) { z := x + y fmt.Println(z) } func main() { for i:= 0; i < 10 ; i++ { go Add(i,i) } }
4.4 并发通信
package main import "fmt" import "sync" import "runtime" var counter int = 0 func Count(lock *sync.Mutex) { lock.Lock() counter++ fmt.Println(counter) lock.Unlock() } func main() { lock := &sync.Mutex{} for i := 0; i < 10; i++ { go Count(lock) } for { lock.Lock() c := counter lock.Unlock() runtime.Gosched() if c >= 10 { break } } }
4.5 channel
package main import "fmt" func Count(ch chan int) { ch <- 1 fmt.Println("Counting") } func main() { chs := make([]chan int,10) for i := 0;i < 10; i++ { chs[i] = make(chan int) go Count(chs[i]) } for _,ch := range(chs) { <-ch } }
4.5.1 基本语法
var chanName chan ElementType var ch chan int var m map[string]chan bool ch := make(chan int) ch <- value // 写入channel value := <-ch // 读取channel
4.5.2 select
select { case <-chan1: // 如果chan1成功读取数据,则进行该case处理语句 case chan2 <- 1: // 如果成功向chan2写入数据,则进行该case处理语句 default: // 如果上面都没有成功,则进入default处理流程 } ch := make(chan int,1) for { select { case ch <- 0: case ch <- 1: } i := <-ch fmt.Println("Value received:",i) }
4.5.3 缓冲机制
4.5.4 超时机制
// 首先,我们实现并执行一个匿名的超时等待函数 timeout := make(chan bool,1) go func() { time.Sleep(1e9) // 等待一秒钟 timeout <- true }() // 然后我们把timeout这个channel利用起来 select { case <-ch: // 从ch中读取到数据 case <-timeout: // 一致没有从ch中读取到数据,但从timeout中读取到了数据 }
4.5.5 channel的传递
type PipeData struct { value int handler func(int) int next chan int } func handle(queue chan *PipeData) { for data := range queue { data.next <- data.handler(data.value) } }
4.5.6 单向channel
var ch1 chan int var ch2 chan<- float64 var ch3 <-chan int ch4 := make(chan int) ch5 := <-chan int(ch4) ch6 := chan<- int(ch4)
4.5.7 关闭channel
close(ch)
x,ok := <-ch
4.6 多核并行化
type Vector []float64 func(v Vector) DoSome(i,n int,u Vector,c chan int) { for ;i < n;i++ { v[i] += u.Op(v[i]) } c <- 1 } const NCPU = 16 func (v Vector) DoAll(u Vecotr) { c := make(chan int,NCPU) for i := 0;i < NCPU;i++ { go v.DoSome(i*len(v)/NCPU,(i+1)*len(v)/NCPU,u,c) } for i := 0;i < NCPU;i++ { <-c } } runtime.GOMAXPROCS(16)
4.7 出让时间片
4.8 同步
4.8.1 同步锁
4.8.2 全局唯一性操作
var a string var once sync.Once func setup() { a = "hello,world" } func dropint() { once.Do(setup) print(a) } func twoprint() { go doprint() go dropinit() }
4.9 完整示例
4.9.1 简单IPC框架
4.9.2 中央服务器
4.9.3 主程序
4.9.4 运行小程序
4.10 小结
第5章 网络编程
5.1 Socket编程
5.1.1 Dial()函数
5.1.2 ICMP示例程序
5.1.3 TCP示例程序
package main import ( "net" "os" "bytes" "fmt" "io" ) func main() { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr,"Usage: %s host:port ",os.Args[0]) os.Exit(1) } service := os.Args[1] conn,err := net.Dial("tcp",service) checkError(err) _,err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n")) checkError(err) result,err := readFully(conn) checkError(err) fmt.Println(string(result)) os.Exit(0) } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr,"Fatal error: %s",err.Error()) os.Exit(1) } } func readFully(conn net.Conn) ([]byte,error) { defer conn.Close() result := bytes.NewBuffer(nil) var buf [512]byte for { n,err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil,err } } return result.Bytes(),nil }
5.1.4 更丰富的网络通信
//func DialTCP(net string,laddr,raddr *TCPAddr) (c *TCPConn,err error) //func DialUDP(net string,laddr,raddr *UDPAddr) (c *UDPConn,err error) //func DialIP(netProto string,laddr,raddr *IPAddr) (*IPConn,error) //func DialUnix(net string,laddr,raddr *UnixAddr) (c *UnixConn,err error) package main import ( "net" "os" "fmt" "io/ioutil" ) func main() { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr,"Usage: %s host:port ",os.Args[0]) os.Exit(1) } service := os.Args[1] tcpAddr,err := net.ResolveTCPAddr("tcp4",service) checkError(err) conn,err := net.DialTCP("tcp",nil,tcpAddr) checkError(err) _,err = conn.Write([]byte("HEAD / HTTP1.0\r\n\r\n")) checkError(err) result,err := ioutil.ReadAll(conn) checkError(err) fmt.Println(string(result)) os.Exit(0) } func checkError(err error) { if err != nil { fmt.Fprintf(os.Stderr,"Fatal error: %s",err.Error()) os.Exit(1) } }
5.2 HTTP编程
5.2.1 HTTP客户端
package main import ( "net/http" ) type OurCustomTransport struct { Transport http.RoundTripper } func (t *OurCustomTransport) transport() http.RoundTripper { if t.Transport != nil { return t.Transport } return http.DefaultTransport } func (t *OurCustomTransport) RoundTrip(req *http.Request) (*http.Response,error) { // 处理一些事情 // 发起HTTP请求 // 添加一些域到req.Header中 return t.transport().RoundTrip(req) } func (t *OurCustomTransport) Client() *http.Client { return &http.Client{Transport:t} } func main() { t := &OurCustomTransport { //... } c := t.Client() resp,err := c.Get("http://example.com") // ... }
5.2.2 HTTP服务端
5.3 RPC编程
5.3.1 Go语言中的RPC支持与处理
5.3.2 Gob简介
5.3.3 设计优雅的RPC接口
5.4 JSON处理
5.4.1 编码为JSON格式
func Marshal(v interface{}) ([]byte,error) type Book struct { Title string Authors []string Publisher string IsPublished bool Price float } gobook := Book { "Go语言编程", ["XuShiwei","HughLv"], "ituring.com.cn", true, 9.99 } b,err := json.Marshal(gobook) b == []byte('{ "Title":"Go语言编程", "Authors":["XuShiwei","HughLv"], "Publisher":"ituring.com.cn", "IsPublished":true, "Price":9.99 }')
5.4.2 解码JSON数据
func Unmarshal(data []byte,v interface{}) error var book Book err := json.Unmarshal(b,&book) book := Book{ "Go语言编程“, ["XuShiwei","HughLv"], "ituring.com.cn", true, 9.99 } b := []byte('{"Title":"Go语言编程","Sales":100000}') var gobook Book err := json.Unmarshal(b,&gobook)
5.4.3 解码未知结构的JSON数据
b := []byte('{ "Title":"Go语言编程", "Authors":["XuShiwei",HughLv"], "Publisher":"ituring.com.cn", "IsPublished":true, "Price":9.99, "Sales":10000 }') var r interface{} err := json.Unmarshal(b,&r) map[string]interface{}{ "Title":"Go语言编程", "Authors":["XuShiwei",HughLv"], "Publisher":"ituring.com.cn", "IsPublished":true, "Price":9.99, "Sales":10000 } gobook,ok := r.(map[string]interface{}) if ok { for k,v := range gobook { switch v2 := v.(type) { case string: fmt.Println(k,"is string",v2) case int: fmt.Println(k,"is int",v2) case bool: fmt.Println(k,"is bool",v2) case []interface{}: fmt.Println(k,"is an array:") for i,iv := range v2 { fmt.Println(i,iv) } default: fmt.Println(k,"is another type not handle yet") } } }
5.4.4 JSON的流式读写
package main import ( "encoding/json" "log" "os" ) func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil { log.Println(err) } for k := range v { if k != "Title" { v[k] = nil,false } } if err := enc.Encode(&v); err != nil { log.Println(err) } } }
5.5 网站开发
5.5.1 最简单的网站程序
package main import ( "io" "log" "net/http" ) func helloHandler(w http.ResponseWriter,r *http.Request) { io.WriteString(w,"Hello,world!") } func main() { http.HandleFunc("/hello",helloHandler) err := http.ListenAndServe(":8080",nil) if err != nil { log.Fatal("ListenAndServ: ",err.Error()) } }
5.5.2 net/http包简介
5.5.3 开发一个简单的相册网站
5.6 小结
第6章 安全编程
6.1 数据加密
6.2 数字签名
6.3 数字证书
6.4 PKI体系
package main import ( "fmt" "crypto/sha1" "crypto/md5" ) func main() { TestString := "Hi,pandaman!" Md5Inst := md5.New() Md5Inst.Write([]byte(TestString)) Result := Md5Inst.Sum([]byte("")) fmt.Printf("%x\n\n",Result) Sha1Inst := sha1.New() Sha1Inst.Write([]byte(TestString)) Result = Sha1Inst.Sum([]byte("")) fmt.Printf("%x\n\n",Result) }
package main import ( "io" "fmt" "os" "crypto/md5" "crypto/sha1" ) func main() { TestFile := "123.txt" infile,inerr := os.Open(TestFile) if inerr == nil { md5h := md5.New() io.Copy(md5h,infile) fmt.Printf("%x %s\n",md5.Sum([]byte("")),TestFile) sha1h := sha1.New() io.Copy(sha1h,infile) fmt.Printf("%x %s\n",sha1h.Sum([]byte("")),TestFile) } else { fmt.Println(inerr) os.Exit(1) } }
6.5 Go语言的哈希函数
6.6 加密通道
6.6.1 加密通信流程
6.6.2 支持HTTPS的Web服务器
package main import ( "fmt" "net/http" ) const SERVER_PORT = 8080 const SERVER_DOMAIN = "localhost" const RESPONSE_TEMPLATE = "hello" func rootHandler(w http.ResponseWriter,req *http.Request) { w.Header().Set("Content-Type","text/html") w.Header().Set("Content-Length",fmt.Sprint(len(RESPONSE_TEMPLATE))) w.Write([]byte(RESPONSE_TEMPLATE)) } func main() { http.HandleFunc(fmt.Sprintf("%s:%d/",SERVER_DOMAIN,SERVER_PORT),rootHandler) http.ListenAndServeTLS(fmt.Sprintf(":%d",SERVER_PORT),"rui.crt","rui.key",nil) }
package main import ( "net" "net/http" "time" "fmt" "crypto/x509" "crypto/rand" "crypto/rsa" "crypto/tls" "encoding/pem" "errors" "io/ioutil" ) const SERVER_PORT = 8080 const SERVER_DOMAIN = "localhost" const RESPONSE_TEMPLATE = "hello" func rootHandler(w http.ResponseWriter,req *http.Request) { w.Header().Set("Content-Type","text/html") w.Header().Set("Content-Length",fmt.Sprint(len(RESPONSE_TEMPLATE))) w.Write([]byte(RESPONSE_TEMPLATE)) } func YourListenAndServeTLS(addr string,certFile string,keyFile string,handler http.Handler) error { config := &tls.Config { Rand: rand.Reader, Time: time.Now, NextProtos: []string{"http/1.1."}, } var err error config.Certificates = make([]tls.Certificate,1) config.Certificates[0],err = YourLoadX509KeyPair(certFile,keyFile) if err != nil { return err } conn,err := net.Listen("tcp",addr) if err != nil { return err } tlsListener := tls.NewListener(conn,config) return http.Serve(tlsListener,handler) } func YourLoadX509KeyPair(certFile string,keyFile string) (cert tls.Certificate,err error) { certPEMBlock,err := ioutil.ReadFile(certFile) if err != nil { return } certDERBlock,restPEMBlock := pem.Decode(certPEMBlock) if certDERBlock == nil { err = errors.New("crypto/tls: failed to parse certificate PEM data") return } certDERBlockChain,_ := pem.Decode(restPEMBlock) if certDERBlockChain == nil { cert.Certificate = [][]byte{certDERBlock.Bytes} } else { cert.Certificate = [][]byte{certDERBlock.Bytes,certDERBlockChain.Bytes} } keyPEMBlock,err := ioutil.ReadFile(keyFile) if err != nil { return } keyDERBlock,_ := pem.Decode(keyPEMBlock) if keyDERBlock == nil { err = errors.New("crypto/tls: failed to parse key PEM data") return } key,err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes) if err != nil { err = errors.New("crypto/tls: failed to parse key") return } cert.PrivateKey = key x509Cert,err := x509.ParseCertificate(certDERBlock.Bytes) if err != nil { return } if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 { err = errors.New("crypto/tls: private key does not match public key") return } return } func main() { http.HandleFunc(fmt.Sprintf("%s:%d/",SERVER_DOMAIN,SERVER_PORT),rootHandler); YourListenAndServeTLS(fmt.Sprintf(":%d",SERVER_PORT),"rui.crt","rui.key",nil) }
6.6.3 支持HTTPS的文件服务器
package main import ( "net/http" ) func main() { h := http.FileServer(http.Dir(".")) http.ListenAndServeTLS(":8001","rui.crt","rui.key",h) }
6.6.4 基于SSL/TLS的ECHO程序
6.7 小结
第7章 工程管理
7.1 Go命令行工具
7.2 代码风格
7.2.1 强制性编码规范
7.2.2 非强制性编码风格建议
package main import "fmt" func Foo(a,b int)(ret int,err error){ if a > b{ return a,nil }else{ return b,nil } return 0,nil } func main() { i,_ := Foo(1,2) fmt.Println("Hello,world",i)}
$ go fmt hello1.go
package main import "fmt" func Foo(a, b int) (ret int, err error) { if a > b { return a, nil } else { return b, nil } return 0, nil } func main() { i, _ := Foo(1, 2) fmt.Println("Hello,world", i) }
7.3 远程import支持
package main import ( "fmt" "github.com/myteam/exp/crc32" )
7.4 工程组织
7.4.1 GOPATH
export GOPATH=~/work/go-proj1:~/work2/goproj2:~/work3/work4/go-proj3
7.4.2 目录结构
7.5 文档管理
7.6 工程构建
7.7 跨平台开发
7.7.1 交叉编译
7.7.2 Android支持
7.8 单元测试
7.9 打包分发
7.10 小结
第8章 开发工具
8.1 选择开发工具
8.2 gedit
8.2.1 语法高亮
8.2.2 编译环境
8.3 Vim
8.4 Eclipse
8.5 Notepad++
8.5.1 语法高亮
8.5.2 编译环境
8.6 LitelIDE
8.7 小结
第9章 进阶话题
9.1 反射
9.1.1 基本概念
9.1.2 基本用法
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 fmt.Println("type:",reflect.TypeOf(x)) v := reflect.ValueOf(x) fmt.Println("type:",v.Type()) fmt.Println("kind is float64:",v.Kind() ==reflect.Float64) fmt.Println("value:",v.Float()) }
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 p := reflect.ValueOf(&x) fmt.Println("type of p:",p.Type()) fmt.Println("settability of p:",p.CanSet()) v := p.Elem() fmt.Println("settability of v:",v.CanSet()) v.SetFloat(7.1) fmt.Println(v.Interface()) fmt.Println(x) }
9.1.3 对结构的反射操作
package main import ( "fmt" "reflect" ) type T struct { A int B string } func main() { t := T{203,"mh203"} s := reflect.ValueOf(&t).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()) } }
9.2 语言交互性
package main import "fmt" /* #include*/ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uinit(i)) } func main() { Seed(100) fmt.Println("Random:",Random()) }
package main /* #includevoid hello() { printf("Hello,Cgo! -- From C world.\n") } */ import "C" func Hello() int { return int(C.hello()) } func main() { Hello() } // #cgo CFLAGS: -DPNG_DEBUG=1 // #cgo linux CFLAGS: -DLINUX=1 // #cgo LDFLAGS: -lpng // #includeimport "C" // #cgo pkg-config: png cairo // #include import "C"
9.2.1 类型映射
9.2.2 字符串映射
9.2.3 C程序
9.2.4 函数调用
9.2.5 编译Cgo
9.3 链接符号
9.4 goroutine机理
9.4.1 携程
9.4.2 携程的C语言实现
9.4.3 协程库概述
package main import ( "flag" "fmt" "os" "strconv" ) var goal int func primeTask(c chan int) { p := <-c if p > goal { os.Exit(0) } fmt.Println(p) nc := make(chan int) go primeTask(nc) for { i := <-c if i%p != 0 { nc <- i } } } func main() { flag.Parse() args := flag.Args() if args != nil && len(args) > 0 { var err error goal,err = strconv.Atoi(args[0]) if err != nil { goal = 100 } } else { goal = 100 } fmt.Println("goal=",goal) c := make(chan int) go primeTask(c) for i := 2;;i++ { c <- i } }
9.4.4 任务
9.4.5 任务调度
9.4.6 上下文切换
9.4.7 通信机制
9.5 接口机理
9.5.1 类型赋值给接口
package main import "fmt" type ISpeaker interface { Speak() } type SimpleSpeaker struct { Message string } func (speaker *SimpleSpeaker) Speak() { fmt.Println("I am speaking? ",speaker.Message) } func main() { var speaker ISpeaker speaker = &SimpleSpeaker{"Hell"} speaker.Speak() }
9.5.2 接口查询
9.5.3 接口赋值