Go语言学习 Day 02

2019-08-29  本文已影响0人  右左君

Go语言学习

[TOC]

Day 02 官方文档补充

格式化

- tab缩进

注释

- 单行//
- 多行/*..*/

命名

- 包名:小写字母命名,不应使用下划线或驼峰记法。
- 接口名
    - 只包含一个方法的接口应当以该方法的名称加上 - er 后缀来命名,如 Reader、Writer、 Formatter、CloseNotifier 等
    - 驼峰记法:Go 中约定使用驼峰记法 MixedCaps 或 mixedCaps 而非下划线的方式来对多单词名称进行命名

分号

Go语言使用分号结尾,但词法分析器会使用一条简单的规则来自动插入分号,代码中不必写分号。

如果新行前的标记为语句的末尾,则插入分号.

if i < f()  // wrong!
{           // wrong! 此处词法分析器会插入分号。
    g()
}

控制结构

Go中无do...while,或者while...,全部用for代替。
switch 要更灵活一点;if 和 switch 像 for 一样可接受可选的初始化语句; 此外,还有一个包含类型选择和多路通信复用器的新控制结构:select。

没有圆括号,而其主体必须始终使用大括号括住。

// if
if x > 0 {
    return y
}

// Like a C for
for init; condition; post { }

// Like a C while
for condition { }

// Like a C for(;;)
for { }

//
for key, value := range oldMap {
    newMap[key] = value
}

// 去掉value
for key := range m {
    if key.expired() {
        delete(m, key)
    }
}

// 去掉key
for _, value := range m {
    //
}

// switch 自上而下逐一进行求值直到匹配为止
func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}

// case 可通过逗号分隔来列举相同的处理条件
func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+', '%':
        return true
    }
    return false
}

函数

func ReadFull(r Reader, buf []byte) (n int, err error) {
    for len(buf) > 0 && err == nil {
        var nr int
        nr, err = r.Read(buf)
        n += nr
        buf = buf[nr:]
    }
    return
}
// Contents returns the file's contents as a string.
func Contents(filename string) (string, error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    defer f.Close()  // f.Close will run when we're finished.

    var result []byte
    buf := make([]byte, 100)
    for {
        n, err := f.Read(buf[0:])
        result = append(result, buf[0:n]...) // append is discussed later.
        if err != nil {
            if err == io.EOF {
                break
            }
            return "", err  // f will be closed if we return here.
        }
    }
    return string(result), nil // f will be closed if we return here.
}

数据

Go 提供了两种分配原语,即内建函数 new 和 make。

var p *[]int = new([]int)       // 分配切片结构;*p == nil;基本没用
var v  []int = make([]int, 100) // 切片 v 现在引用了一个具有 100 个 int 元素的新数组


func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}

初始化

const (
    ZERO = iota //0
    ONE = 1
    TWO = iota //1
)

方法

接口和其他类型

空白标识符

package main

import (
    "fmt"
    "io"
    "log"
    "os"
)

var _ = fmt.Printf // For debugging; delete when done. // 用于调试,结束时删除。
var _ io.Reader    // For debugging; delete when done. // 用于调试,结束时删除。

func main() {
    fd, err := os.Open("test.go")
    if err != nil {
        log.Fatal(err)
    }
    // TODO: use fd.
    _ = fd
}

并发

Go 语言另辟蹊径,它将共享的值通过信道传递,实际上,多个独立执行的线程从不会主动共享

不要通过共享内存来通信,而应通过通信来共享内存。

Goroutine 具有简单的模型:它是与其它 goroutine 并发运行在同一地址空间的函数。它是轻量级的, 所有消耗几乎就只有栈空间的分配。而且栈最开始是非常小的,所以它们很廉价, 仅在需要时才会随着堆空间的分配(和释放)而变化。

Goroutine 在多线程操作系统上可实现多路复用,因此若一个线程阻塞,比如说等待 I/O, 那么其它的线程就会运行。Goroutine 的设计隐藏了线程创建和管理的诸多复杂性。

Channels

Parallelization

尽管 Go 的并发特性能够让某些问题更易构造成并行计算, 但 Go 仍然是种并发而非并行的语言,且 Go 的模型并不适合所有的并行问题

Select

select 语句用于在多个发送/接收信道操作中进行选择。
select 语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。
该语法与 switch 类似,所不同的是,这里的每个 case 语句都是信道操作。

package main

import (  
    "fmt"
    "time"
)

func server1(ch chan string) {  
    time.Sleep(6 * time.Second)
    ch <- "from server1"
}
func server2(ch chan string) {  
    time.Sleep(3 * time.Second)
    ch <- "from server2"

}
func main() {  
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    select {
    case s1 := <-output1:
        fmt.Println(s1)
    case s2 := <-output2:
        fmt.Println(s2)
    }
}

//from server2

错误

type error interface {
    Error() string
}

// PathError 记录一个错误以及产生该错误的路径和操作。
type PathError struct {
    Op string    // "open"、"unlink" 等等。
    Path string  // 相关联的文件。
    Err error    // 由系统调用返回。
}

func (e *PathError) Error() string {
    return e.Op + " " + e.Path + ": " + e.Err.Error()
}


//PathError 的 Error 会生成如下错误信息:

//open /etc/passwx: no such file or directory

Panic

panic 函数,它会产生一个运行时错误并终止程序 (但请继续看下一节)。该函数接受一个任意类型的实参(一般为字符串),并在程序终止时打印。 它还能表明发生了意料之外的事情,比如从无限循环中退出了。

Recover

WEB



package main

import (
    "flag"
    "html/template"
    "log"
    "net/http"
)
// 地址端口
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18

//模板
var templ = template.Must(template.New("qr").Parse(templateStr))

//主程序
func main() {
    flag.Parse()
    //将 QR 函数绑定到服务器的根路径
    http.Handle("/", http.HandlerFunc(QR))
    //调用 http.ListenAndServe 启动服务器
    err := http.ListenAndServe(*addr, nil)
    if err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}

//表单值传给 templ.Execute 执行因而重写了 HTML 文本
func QR(w http.ResponseWriter, req *http.Request) {
    templ.Execute(w, req.FormValue("s"))
}

//从 {{if .}} 到 {{end}} 的代码段仅在当前数据项(这里是点 .)的值非空时才会执行。
const templateStr = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{{if .}}
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={{.}}" />
<br>
{{.}}
<br>
<br>
{{end}}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>
</body>
</html>
`

FAQ

debugserver or lldb-server not found: install XCode's command line tools or lldb-server

重新安装下xcode-select就好了

xcode-select --install

reference

上一篇 下一篇

猜你喜欢

热点阅读