Golang基础

Hello World!

package main

import "fmt"

func main() {
    fmt.Println("Hello World!")
}

变量定义

package main

import "fmt"

func varInit() {
    var a, b int = 3, 4
    var s = "Hello"
    c, d := true, 3.14
    var (
        e = "你"
        f = 6
    )
    fmt.Println(a, b, s, c, d, e, f)
}

func main() {
    varInit()
}

内建类型

  • bool

  • string

  • 有无符号的int, int8, int16, int32, int64

  • uintptr

  • byte = uint8

  • rune= uint32

  • float32, float64, complex64, complex128

  • 强制类型转换

常量与枚举

package main

import "fmt"

func consts() {
    const filename = "a.txt"
    const (
        a = 1
        b = 2
    )
    fmt.Println(filename, a, b)
}

func enums() {
    const (
        windows = iota
        linux
        mac
    )
    const (
        b = 1 << (10 * iota)
        kb
        mb
        gb
        tb
        pb
    )
    fmt.Println(windows, linux, mac)
    fmt.Println(b, kb, mb, gb, tb, pb)

}

func main() {
    consts()
    enums()
}

条件语句

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    const filename = "a.txt"
    if content, err := ioutil.ReadFile(filename); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(content)
    }
}

循环语句

package main

import (
    "fmt"
    "strconv"
)

func convertToBin(n int) string {
    result := ""
    for ; n > 0; n /= 2 {
        result = strconv.Itoa(n%2) + result
    }
    return result
}
func main() {
    fmt.Println(convertToBin(5))
}

函数

package main

import (
    "fmt"
)

func eval(a, b int, op string) (int, error) {
    switch op {
    case "+":
        return a + b, nil
    case "-":
        return a - b, nil
    case "*":
        return a * b, nil
    case "/":
        return a / b, nil
    default:
        return 0, fmt.Errorf("unsupported operation: %s", op)

    }
}
func main() {
    fmt.Println(eval(1, 2, "*"))
}

指针

package main

import (
    "fmt"
)

func swap(a, b *int) {
    *a, *b = *b, *a
}

func main() {
    a, b := 2, 3
    // go里的参数传递都是值传递,对于比较大的数据使用指针可以避免资源浪费
    swap(&a, &b)
    fmt.Println(a, b)
}
ntln(a, b)
}

数组

package main

import "fmt"

func main() {
    // 数组是值类型
    var (
        arr1 [6]int
        arr2 = [3]int{1, 2, 3}
        arr3 = [...]int{4, 5, 6}
    )
    fmt.Println(arr1, arr2, arr3)
    // range关键字
    for i := range arr2 {
        fmt.Println(i)
    }
    for i, v := range arr2 {
        fmt.Println(i, v)
    }
}

切片

package main

import "fmt"

func modifyArr(s []int) {
    s[0] = 99
}

func printSlice(s []int) {
    fmt.Printf("len=%d, cap=%d", len(s), cap(s))
    fmt.Println("")
}

func main() {
    var sli []int // nil
    printSlice(sli)
    sli = append(sli, 0)
    printSlice(sli)
    sli1 := make([]int, 8)
    fmt.Println(sli1)

    arr := [...]int{0, 1, 2, 3, 4}
    // s是对arr的一个view,使用切片可以不传指针而方便地修改数组
    s := arr[1:3]
    fmt.Println(s)
    modifyArr(s)
    fmt.Println(s)   // [99 2]
    fmt.Println(arr) // [0 99 2 3 4]
    s1 := s[1:3]
    fmt.Println(s1) // [2 3]
    // slice: ptr(指向切片起始位置), len,cap(从起始位置到数组末尾的长度)
    // s[i]不可超越len,s[:n]不可超越cap
    s2 := append(s1, 100)
    fmt.Println(s2)  // [2, 3, 100]
    fmt.Println(arr) // [0 99 2 3 100]

    originSSlice := []int{0, 1, 2, 3, 4}
    destSlice := make([]int, 16)
    copy(destSlice, originSSlice)
    fmt.Println(destSlice) // [0 1 2 3 4 0 0 0 0 0 0 0 0 0 0 0]

    deleteRes := append(originSSlice[:2], originSSlice[3:]...)
    fmt.Println(deleteRes)    // [0 1 3 4]
    fmt.Println(originSSlice) // [0 1 3 4 4]
}

Map

package main

import "fmt"

func main() {
    m := map[string]int{
        "Windows": 0,
        "Mac":     1,
        "Linux":   100,
    }
    m1 := make(map[string]string)
    var m2 map[string]int
    fmt.Println(m1, m2 == nil) // map[] true
    // python3.5之后dict是有序的,但map是无序的
    for k, v := range m {
        fmt.Println(k, v)
    }
    fmt.Println(m["android"]) // 会取到对应类型的零值
    val, ok := m["nothing"]
    fmt.Println(val, ok) // 0 false
    delete(m, "Windows")
    fmt.Println(m)
}
寻找最长不含重估字符的字串
package main

func solute(s string) {
    m := make(map[rune]int)
    start := 0
    maxLen := 0
    for i, v := range []rune(s) {
        if old, ok := m[v]; ok && old >= start {
            start = old + 1
        }
        if i-start+1 > maxLen {
            maxLen = i - start + 1
        }
        m[v] = i
    }
    print(maxLen)
}

func main() {
    solute("pwwkew")
}

结构体

package main

import "fmt"

type TreeNode struct {
    value       int
    left, right *TreeNode
}

func CreateNode(value int) *TreeNode {
    // 返回局部变量的地址并不会使外界调用时的代码出现问题
    return &TreeNode{value: value}
}

func (node TreeNode) PrintNode() {
    fmt.Println(node.value)
}

// 需要改变内容、结构过大时应使用指针接收者;保持接收者类型一致性
// 接受者类型并不会直接影响调用

func (node *TreeNode) SetNode(value int) {
    // 使用指针接收者以方便修改数据
    if node == nil {
        // nil指针也可以调用方法
        fmt.Println("Ignored")
        return
    }
    node.value = value
}

func (node *TreeNode) Traverse() {
    if node == nil {
        // 边界条件
        return
    }
    node.left.Traverse()
    node.PrintNode()
    node.right.Traverse()
}

func main() {
    root := TreeNode{value: 3}
    root.left = &TreeNode{4, nil, nil}
    root.right = &TreeNode{5, nil, nil}
    root.right.left = new(TreeNode)
    root.left.right = CreateNode(6)
    root.Traverse()
}

封装

  • 每个目录为一个包(不要求包名和目录名一致)

  • main包包含可执行入口

  • 为结构定义的方法必须放在同一个包内(的相同或者不同文件)

针对包的权限:标识符首字母大写代表public、首字母小写代表private

扩充已有(系统或自定义)类型

  • 使用组合
package trn

import "fmt"

type TreeNode struct {
    Value       int
    Left, Right *TreeNode
}

func CreateNode(value int) *TreeNode {
    return &TreeNode{Value: value}
}

func (node *TreeNode) PrintNode() {
    fmt.Println(node.Value)
}

func (node *TreeNode) SetNode(value int) {
    if node == nil {
        fmt.Println("Ignored")
        return
    }
    node.Value = value
}

func (node *TreeNode) Traverse() {
    if node == nil {
        return
    }
    node.Left.Traverse()
    node.PrintNode()
    node.Right.Traverse()
}



package main

import "go_code/trn"

type myTreeNode struct {
    node *trn.TreeNode
}

func (myNode *myTreeNode) TraverseL() {
    if myNode == nil || myNode.node == nil {
        return
    }
    (&myTreeNode{myNode.node.Left}).TraverseL()
    (&myTreeNode{myNode.node.Right}).TraverseL()
    myNode.node.PrintNode()
}

func main() {
    root := trn.TreeNode{Value: 3}
    root.Left = &trn.TreeNode{4, nil, nil}
    root.Right = &trn.TreeNode{5, nil, nil}
    root.Right.Left = new(trn.TreeNode)
    root.Left.Right = &trn.TreeNode{Value: 6}
    test := myTreeNode{&root}
    test.TraverseL()
}
  • 定义别名
package queue

type Q []int

func (q *Q) Push(value int) {
    *q = append(*q, value)
}

func (q *Q) Pop() int {
    tail := (*q)[len(*q)-1]
    *q = (*q)[:len(*q)-1]
    return tail
}

func (q *Q) IsEmpty() bool {
    return len(*q) == 0
}
package main

import (
    "fmt"
    "go_code/queue"
)

func main() {
    q := queue.Q{1}
    q.Push(2)
    q.Push(3)
    fmt.Println(q)
    fmt.Println(q.IsEmpty())
    fmt.Println(q.Pop())
    fmt.Println(q)
    fmt.Println(q.IsEmpty())
    fmt.Println(q.Pop())
    fmt.Println(q)
    fmt.Println(q.IsEmpty())
}
  • 内嵌
package main

import "go_code/trn"

type myTreeNode struct {
    *trn.TreeNode // 内嵌
}

func (myNode *myTreeNode) Traverse() {
    if myNode == nil || myNode.TreeNode == nil {
        return
    }
    // 减少代码量myNode.TreeNode.Left -> myNode.Left
    (&myTreeNode{myNode.Left}).Traverse()
    (&myTreeNode{myNode.Right}).Traverse()
    myNode.PrintNode()
}

func main() {
    // myTreeNode自动获取内嵌结构体的属性和方法
    root := myTreeNode{&trn.TreeNode{Value: 3}}
    root.Left = &trn.TreeNode{4, nil, nil}
    root.Right = &trn.TreeNode{5, nil, nil}
    root.Right.Left = new(trn.TreeNode)
    root.Left.Right = &trn.TreeNode{Value: 6}
    // 相较于传统面向对象的重载,内嵌仍可调用被shadowed的方法,
    // 但不是通过子类对象赋值基类
    root.Traverse()
    root.TreeNode.Traverse()
}

依赖管理

  1. GOPATH:摆烂管理

  2. GO VENDER:打补丁

  3. GO MOD:直接用

GOPATH
go env -w GOPATH=
go env -w GO111MODULE=off

# 临时
export GOPATH=
export GO111MODULE=off

mkdir src

go get -u xxx.xxx.org/xxx
GO VENDER

每个项目下自建vender目录管理自己的库

GO MOD

import 路径 = go mod 下的module name + 包相对于go mod的相对目录

go env -w GO111MODULE=on
# 切换本地代理
go env -w GOPROXY=https://goproxy.cn,direct
go get -u xxx.xxx.org/xxx@vn.nn
# 清理无用版本
go mod tidy
旧项目迁移GO MOD
go env -w GO111MODULE=on
# 切换本地代理
go env -w GOPROXY=https://goproxy.cn,direct
go mod init modname
# 检查编译是否可以通过,编译全部子目录文件可以考虑使用go install ./...
go build ./...

go中没有类似python中的__name__ == '__main__'的用法,所以如果要写不同的main入口只能将其放入不同目录

接口

  • Go中接口的实现是隐式的
// retriever/main.go
package main

import (
	"fmt"
	"learn1/retriever/test"
	"learn1/retriever/web"
	"time"
)

type Retriever interface {
	Get(url string) string
}

func download(r Retriever) string {
	return r.Get("http://www.baidu.com")
}

func main() {
	var r Retriever
	r = web.Retriever{TimeOut: time.Minute}
	fmt.Println(download(r))
	r = test.Retriever{Contents: "测试"}
	fmt.Println(download(r))
}


// retriever/test/retriever.go
package test

type Retriever struct {
	Contents string
}

func (r Retriever) Get(url string) string {
	return r.Contents
}


// retriever/web/retriever.go
package web

import (
	"net/http"
	"net/http/httputil"
	"time"
)

type Retriever struct {
	TimeOut time.Duration
}

func (r Retriever) Get(url string) string {
	response, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	bytes, err := httputil.DumpResponse(response, true)
	response.Body.Close()
	if err != nil {
		panic(err)
	}
	return string(bytes)
}
  • 接口变量包含了实现者类型信息和实现者值信息
// retriever/main.go
package main

import (
	"fmt"
	"learn1/retriever/test"
	"learn1/retriever/web"
	"time"
)

type Retriever interface {
	Get(url string) string
}

func download(r Retriever) string {
	return r.Get("http://www.baidu.com")
}

func main() {
	var r Retriever
	r = web.Retriever{TimeOut: time.Minute}
	//fmt.Println(download(r))
	r = test.Retriever{Contents: "测试"}
	//fmt.Println(download(r))
	// type assertion
	if testRetriever, ok := r.(test.Retriever); ok {
		fmt.Println(testRetriever.Contents)
	} else {
		fmt.Println("web.Retriever")
	}
}
  • 接口变量自带指针
  • 接口变量同样采用值传递,几乎不需要使用接口的指针
  • 指针接收者实现只能以指针方式使用,值接收者则无此限制
  • 任何类型:interface{}
  • 接口的组合
type Retriever interface {
	Get(url string) string
}

type Poster interface {
	Post(url string) string
}

type WebTool interface {
	Retriever
	Poster
	Delete(target map[string]string) bool
}
  • 常用系统接口(很像Python中的某些魔法方法)
    1. Stringer
    2. Reader
    3. Writer

函数式编程

闭包

错误处理与资源管理

defer

  1. 类似栈,在函数返回前执行,多个defer语句先定义的后执行
  2. defer语句中的变量定义时确定值

panic

  1. 停止当前函数执行
  2. 一直向上范围,执行每一层的defer
  3. 如果没有遇见recover,程序退出

recover

  1. 仅在defer调用中使用
  2. 获取panic的值
  3. 可重新panic

测试

表格驱动测试

// learn_t/triangle.go
package main

import "math"

func triangle(a, b int) int {
	return int(math.Sqrt(float64(a*a + b*b)))
}


//learn_t/triangle_test.go
package main

import "testing"

func TestTriangle(t *testing.T) {
	tests := []struct{ a, b, c int }{
		{3, 4, 5},
		{5, 12, 13},
		{6, 8, 10},
		{30000, 40000, 50001},
	}
	for _, te := range tests {
		if actual := triangle(te.a, te.b); actual != te.c {
			t.Errorf("triangle(%d, %d) got %d expected %d", te.a, te.b, actual, te.c)
		}
	}

}
// terminal
// go test .

代码覆盖率

#代码覆盖率
go test -coverprofile=c.out
#输出html
go tool cover -html=c.out
// 性能测试
// learn_t/triangle_test.go
package learn1

import "testing"

func BenchmarkTriangle(b *testing.B) {
	x, y, z := 3, 4, 5
	for i := 0; i < b.N; i++ {
		if actual := triangle(x, y); actual != z {
			b.Errorf("triangle(%d, %d) got %d expected %d", x, y, actual, z)
		}
	}

}
// terminal
// go test -bench .

原文地址:http://www.cnblogs.com/missfxy/p/16930551.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性