Go语言圣经

项目初始

IDEA配置

如果想要在IDEA中 产生可执行的二进制文件,在WINDOW exe, Linux 在IDEA中如下配置
-o bin.main 修改二进制输出的名
在这里插入图片描述

引用其他包文件
package calc
func Add(a, b int) int {
	return a + b
}

* Add 函数必须要大写,大写属于public 才能够让其他包引用 ,不是大写 属于私有方法
* 同一个文件下面的函数变量名称不能重复
* 
  • GIF 动态画面
package main

import (
	"image"
	"image/color"
	"image/gif"
	"io"
	"log"
	"math"
	"math/rand"
	"net/http"
	"os"
	"time"
)

var palette = []color.Color{color.White, color.Black}

const (
	whiteIndex = 0 // 画板中第一种颜色
	blackIndex = 1 // 画板中第二种颜色
)

func lissajous(out io.Writer) {
	const (
		cycles  = 5
		res     = 0.001
		size    = 100
		nframes = 64
		delay   = 8
	)
	freq := rand.Float64() * 3.0
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < cycles*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	err := gif.EncodeAll(out, &anim)
	if err != nil {
		return
	}
}
func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	if len(os.Args) > 1 && os.Args[1] == "web" {
		handler := func(w http.ResponseWriter, r *http.Request) {
			lissajous(w)
		}
		http.HandleFunc("/", handler)
		log.Fatal(http.ListenAndServe("localhost:8080", nil))
		return
	}
	lissajous(os.Stdout)
}

  • 构建简单 统计的服务器
package main

import (
	"fmt"
	"log"
	"net/http"
	"sync"
)

// 构建一个简单的 web 服务 能够流量计数统计
var mu sync.Mutex
var count int

func handler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	count++
	mu.Unlock()
	_, err := fmt.Fprintf(w, "URL.path = %q\n", r.URL.Path)
	if err != nil {
		return
	}
}

func counter(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	_, err := fmt.Fprintf(w, "Count %d\n", count)
	if err != nil {
		return
	}
	mu.Unlock()

}

func main() {
	// 回声请求的调用处理函数
	http.HandleFunc("/", handler)
	http.HandleFunc("/counter", counter)
	log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
  • 变量第一区别
var :多用于全局变量
:= 简短声明多用于局部变量
new() 分配内存函数 返回函数地址
make() 只使用于 map,chan, slice
  • init()函数
1. 同一个包下面可以有多个init 函数
2. 自动执行,不需要调用 类似于Java中构造器函数
3. 方法名称 init() ,init()main() 函数前执行, 多个init() 初始化化原则(依赖顺序初始化)
  • go 语言中异常处理 通过是使用 if 方式
if f,err := os.Open(fname); err != nil {
    return err
}else {
	f.Stat()
	f.Close()
}

  • 常量
4. 使用const 定义,如果在定义过程中没有初始化值 自动找前一个赋值常量
const (
	a = 1
	b
	c = 2
	d 
) // 1 1 2 2
5. 常量生成器: iota :0 开始取值 逐项+1 
使用在枚举类中数字表示
type Weekday int
const (
	Sunday Weekday = iota
	Monday
	Tuesday
)
  • Go 中函数有多个返回值
func op(x, y int) (int, error) {
	if (0 == y){
		return -1, errors.New("ch除数不能为0")
}else {
	return x /y, nil
}
}

  • Go 中异常处理
    Go 语言不像Java 有异常处理的控制流, 使用 nil 和非nil 表示程序来是否运行成功, 并且非空值一般使用错误消息的字符串Errors.New(""), fmt.Errorf("parseing %s") 所有在Go中 清晰说明返回值的意义非常重要
    Go语言有异常机制,但是针对程序BUG导致的预料之外的错误,对于常规的错误方法初始化通过返回字符串类型进行处理
6. s使用 fmt.Errorf 格式化一条错误消息并且返回一个新的错误值,在原始的错误消息不断添加额外的上下文信息 创建一个可读的错误描述,-- 清晰的因果链;
7. 错误消息频繁串联起来,消息字符串首字母 不应该大写并且避免换行

Go语言中错误的消息设计时候 慎重,最好包含充足的相关信息,并且保持一致性,保持统一的形式和错误的处理方式

  • 对于不固定或者不可预测的错误
比如对服务器在短时间内进行 指数退避策略进行重试
if err := WaitForSrver(url); err != nil {
	fmt.Fprintf(os.Stderr, "site is down: %v\n", err)
	os.Exit(1)
}
Go 语言错误处理有特定的规律, 成功的逻辑不会放在else 块,在外层的作用域,一般看到 if err 之后,不会有太多的else

  • 捕获迭代变量
    在Go 语言的for 循环中,在循环里创建所有的函数变量共享相同的变量 循环中函数变量共享相同的地址,不是副本,导致在循环删除时候 如果不定义一个临时变量进行存储,最终删除知识最后一次
var rmdirs [] func()
for _, d := range tempDirs(){
	dir :=d // 必须要使用局部变量 声明内部的dir ,并且外部的dir 进行初始化
	os.MkdirAll(dir, 0775)
	rmdirs = append(rmdirs, func() {
		os,RemoveAll(dir)
})
}
  • defer 延迟函数
    defer go中一种延迟调用的机制,defer 函数只有在当前函数执行完毕后才会执行,遵守的栈的结果 场景在于 释放资源, 保留是入栈时候的值
8. goreturn 语句并不是原子性操作, defer1之后 2之前
 1. 将返回值赋值个一个变量
 2. 执行RET指令
9.  -- 输出结果 10 保存的是入栈那一刻的值
	 x := 10
	defer func(a int) {
		fmt.Printf("%d", a)
	}(x)
	x++
10. 输出结果 11 传入的是地址
	x := 10
		defer func(a *int) {
			fmt.Printf("%d", *a)
		}(&x)
		x++
11. 输出结果 11 是具名函数。即返回值带有名字。这样我们在执行defer的时候相当于修改了返回值的值。所以为11
	func test()(x int)  { -- 属于具体名称函数 ,返回值带有函数名称
	 x = 10
	 defer func() {
	 	x++
	 }()
12. 闭包函数 返回值 10
13. func test1() int {
	x := 10
	defer func() {
		x++
	}()
	// ans = x
	// -------- defer x = x+1
	// return x
	return x
}
  • paninc
    当函数发生paninc 时候,会严重的退出函数,使用defer 延迟函数方式倒序方式打印出堆栈函数
    因此对于paninc 函数 需要进行Recover 函数,比如在WEB程序中出现paninc 需要关闭所有的链接 比paninc 方式号
    recorver 终止当前的paninc 状态并且返回paninc 函数, 函数在paninc地方跳转到recover函数 ,与 Java try..catch 有不一样
    因此:recover 函数 让输出paninc 信息,WEB服务器在持续运行
package main

import "fmt"

func main() {

	defer func() {
		err := recover()
		// 恢复
		fmt.Println("recorver error:", err)
	}()

	for i := 0; i < 10; i++ {
		if i == 5 {
			// painc 程序退出
			panic("i == 5")
		}
	}
}
-- recover 函数 捕获到 paninc 函数 ,与 Java try..catch 不一样,在 i == 5 跳出主函数 ,执行 延迟函数中 recover(),没有执行 i= 6; 不会执行for 循环
  • Go中 OOP 面向对象编程
    go 语言中通过结构体方式,不同于java 中类,GO语言形成一个对象 最重要原则: 组合 + 封装
方法声明
  1. 方法声明与普通函数相似,只是与普通的函数多了一个参数, 将 Distance 方法属于某个类型方式, 普通函数属于 包级别方法
func Distance(p, q Point) float64 {
	return p * q
}
// Point类型函数, p 称为方法接收者, 使用类型的简写
func (p Point) Distance(q Point) float64 {
		return p.x-q.x + p.Y- q.Y
}
类型方法调用: p:= Point{1,2}
			q:= Point{3,4}
			p.Distance(q) -- 选择子 ,注意 方法和名称属于同一个命名空间,在Point类型中声明一个与属性相同的方法名称会报错
  1. 指针接收者方法:
    类型任何一个方法使用指针接收者,其他方法使用指针接收者
 主函数会赋值每一个实参变量,如果想更新一个变量,或者变量太大不像时刻复制实参,需要使用指针传递变量地址, 这样使用 指针类型的接收者;
 1. 定义一个指针 & 取其地址
 2. p Point 类型普通变量 Run 属于指针接收者
    p.Run() // 编译器 隐式转换 (&p).Run() -- 普通类型变量调用指针方法
 3. p3 = &Point{"jack", 1} p3.Say() ,其中 Say() 普通的方法
	p3.Say() // 编译器隐式转换 (*p3).Say()  -- 指针调用非指针函数
	P3:实参类型,Run()方法 形参类型
3. 变量类型与方法 属于同一类型 调用OK
  • nil 是合法的接收者
  • nil 表示是一个空链表, nil 是类型中有意义0值
    类型中如果允许nil 接收者需要在注释中 显示的表明
type IntList struct {
	value int
	tail *IntList
}

func (list *IntList) Sum() int {
	if nil ==list {
		return 0
 }
 return list.value + list.tail.sum()
}
  • 封装
    在Go中丹云是包 不是类型也不是类, 封装类似Java中 私有变量,protect变量
  1. 使用放不能直接修改对象的变量,不需要更多语句检查变量值
  2. 隐藏实现细节防止使用放依赖属性发生变化,设计者更加灵活修改API实现不破坏兼容性
  3. 防止使用者肆意修改对象内的变量
    变量和方法不能通过对象方位到,这种方式叫做封装,也叫数据隐藏
    Go 只有一种方式控制命名可见性,定义时候 首字母大写的标识符,是可以从包中导出, 同样也适用于结构体内字段和类型中方法, 要封装一个对象,必须使用结构体
// 只能在定义InSet 包内使用
type InSet struct {
	words [] unit64
}
// 其他包内被使用,重新定义 IntSet 为 一个Slice 类型 功能基本相同,想要修改 words值 需要使用 *s 指针类型
type InSet [] unit64

// bytes.Buffer 类型 结构体有 buf 首字母不是大写,其他包不能引用,这块空间额外的[64]byte ,使用者感觉性能提升但是不会关系内部实现
type Bffer struct {
	buf [] byte
	initial [64] byte
}
接口

Go 一个具体类型,无需进行接口声明,只需要提供实现接口方法即可
GO语言中一种类型接口类型,属于抽象类型,并没有暴露数据的布局或者内部结构。
一个接口类型定义了一套方法,一个具体类型实现该接口,那么实现该接口类型中定义的所有的方法。
当一个表达式实现了一个接口时候,那么这个表达才可以赋值给该接口

1. B 类型需要实现A类型的所有方法,才能认为B类型实现A接口
2. 传入任何的参数,需要通过接口 进行接口断言
3. flag.value进行参数解析,进行命令行参数的解析
  • 接口值
    一个接口类型的值分为两部分, 一个具体类型 和该类型的一个值,两者称为 接口的 动态类型和动态值,类型描述符表述,一个接口有多个具体的实现
	var w io.Writer
	w = os.Stdout // 动态类型:os.File 类型描述符, 动态值为os.Stdout 副本
	w= new(bytes.Buffer)

含有空指针的非空接口
空的接口值(不包含任何信息)与动态值为nil的接口值不一样的, 分配了指针但是其值没有调用使用发生paninc
动态值是nil,但是其动态类型存在 在判断时候发现是正确的
解决方案: 保持接口的动态类型 一致; 不要 定义的变量接口类型和函数动态类型不一致,导致发生空指针的非空接口, w != nil 比较动态类型

  • 类型断言
    类型断言作用在接口值上操作,x(T) ,X表示一个接口类型的表达式,断言检查 动态类型是否满足指定的断言类型
var w io.Writer
w = os.Stdout
// 判断接口的类型断言
f := w.(*os.File) // 成功 f == os.Stdout 

var w io.Writer
	w = os.Stdout
	// T 是具体类型, 检查X的动态类型是否就是T
	// x.(T) 如果T 是接口类型,检查 x 的动态类型是否满足 T
	f := w.(*os.File)
	fmt.Println("%T", f.Name())
  • 使用类型断言识别错误
4. 使用字符串方式判断是否包含某种错误字符串 不建议
5. 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言圣经》是一本广受好评的教材,旨在帮助读者系统地学习和掌握Go语言。这本书以简明清晰的方式介绍了Go语言的各种特性、语法和用法,是入门和进阶者的理想选择。 首先,该书提供了对Go语言基础知识的全面介绍。它从简单到复杂地解释了Go语言的基本概念,诸如变量、函数、循环和条件语句等等。通过丰富的例子和练习,读者能够逐步理解和掌握这些概念。 其次,该书详细介绍了Go语言的高级特性和用法。读者可以学习到Go语言的面向对象编程、并发编程、网络编程等关键技术。并发编程是Go语言的一个独特特性,对于提高程序性能和扩展能力非常重要。 此外,该书还包含了对常见问题和陷阱的讲解,帮助读者避免一些常见的错误和陷阱。同时,书中提供了大量的案例和实践项目,读者可以通过实际操作来巩固所学内容。 《Go语言圣经》以其简洁明了的风格和对细节的深入讲解而闻名。无论是作为初学者的入门指南,还是作为有经验的开发者的参考书,这本书都能满足读者的需求。此外,该书的PDF版本能够方便地在线或离线阅读,为读者提供了更加便捷的学习体验。 综上所述,《Go语言圣经》是一本内容丰富、权威性强的优秀教材。它不仅适合Go语言的初学者,也适用于那些想要深入学习和掌握Go语言的开发者。无论是在线阅读还是PDF版本,读者都能够方便地获取和利用这本宝贵的学习资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值