目录

  • 1.包
  • 2. 函数
  • 3. 变量
  • 4. For
  • 5. If
  • 6. Switch
  • 7. defer
  • 8. 指针
  • 9. 结构体
  • 10. 数组
  • 11. 切片
  • 12. Range
  • 13. 映射
  • 15.方法
  • 16. 接口
  • 17. Stringer
  • 18. 错误
  • 19. Reader
  • 19. Go 程
  • 20. 信道
  • 20. select 语句
  • 21. sync.Mutex

环境配置
1 go语言安装
https://go-zh.org/doc/install#windows

2 goland ide 安装与配置
http://8000.woa.com/v2/Software/Detail/106

3 go 语言基础快速入门
https://tour.go-zh.org/welcome/1

1.包

单个:
import "fmt"
多个:
import ("fmt""math/rand"
)

导出名
在 Go 中,如果一个名字以大写字母开头,那么它就是已导出的。任何未导出的名字在该包外均无法访问。

2. 函数

2.1 类型在变量名之后:

func add(x int, y int) int

2.2 两个变量相同可省略:

func add(x, y int) int

2.3 函数可以返回任意数量的返回值:

func swap(x, y string) (string, string)

2.4 Go 的返回值可被命名,它们会被视作定义在函数顶部的变量:

func split(sum int) (x, y int)

3. 变量

3.1 var语句声明类型在最后:

var c, python, java bool

3.2 变量声明可以包含初始值,每个变量对应一个,变量会从初始值获得类型:

var c,python, java = true, false, "no!"

3.3 简洁赋值语句 := 可在类型明确的地方代替 var 声明, := 结构不能在函数外使用:

c, python, java := true, false, "no!"

3.4 基本类型Go 的基本类型有

bool
string
int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名 表示一个 Unicode 码点
float32 float64
complex64 complex128

int, uint 和 uintptr 在 32 位系统上通常为 32 位宽,在 64 位系统上则为 64 位宽

3.5 语法块

var (ToBe   bool       = falseMaxInt uint64     = 1<<64 - 1z      complex128 = cmplx.Sqrt(-5 + 12i)
)

3.6 零值
数值类型为 0,
布尔类型为 false,
字符串为 “”(空字符串)。

3.7 类型转换

var f float64 = float64(i)
f := float64(i)

3.8 类型推导
在声明一个变量而不指定其类型时(即使用不带类型的 := 语法或 var = 表达式语法),变量的类型由右值推导得出。不过当右边包含未指明类型的数值常量时,新变量的类型就可能是 int, float64 或 complex128 了,这取决于常量的精度:

3.9 常量声明

const Pi = 3.14

常量不能用 := 语法声明。

3.10 数值常量
一个未指定类型的常量由上下文来决定其类型。

4. For

4.1

for i := 0; i < 10; i++ {sum += i
}

初始化语句通常为一句短变量声明,该变量声明仅在 for 语句的作用域中可见。
后面的三个构成部分外没有小括号, 大括号 { } 则是必须的。
4.2
for 是 Go 中的 while

for sum < 1000 {sum += sum
}

5. If

5.1

if x < 0 {return sqrt(-x) + "i"
}

表达式外无需小括号 ( ) ,而大括号 { } 则是必须的。
5.2 if 的简短语句

if v := math.Pow(x, n); v < lim {return v
} else {fmt.Printf("%g >= %g\n", v, lim)
}

同 for 一样, if 语句可以在条件表达式前执行一个简单的语句。
该语句声明的变量作用域仅在 if 之内。

6. Switch

6.1 Go 自动提供了在这些语言中每个 case 后面所需的 break 语句。 除非以 fallthrough 语句结束,否则分支会自动终止。
case 无需为常量,且取值不必为整数。

switch os := runtime.GOOS; os {case "darwin":fmt.Println("OS X.")case "linux":fmt.Println("Linux.")default:// freebsd, openbsd,// plan9, windows...fmt.Printf("%s.\n", os)
}

6.2 switch 的 case 语句从上到下顺次执行,直到匹配成功时停止。
6.3 没有条件的 switch 同 switch true 一样。

switch {case t.Hour() < 12:fmt.Println("Good morning!")case t.Hour() < 17:fmt.Println("Good afternoon.")default:fmt.Println("Good evening.")
}

7. defer

7.1 defer 语句会将函数推迟到外层函数返回之后执行。

defer fmt.Println("world")
fmt.Println("hello")

7.2 推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。

for i := 0; i < 10; i++ {defer fmt.Println(i)
}

8. 指针

指针保存了值的内存地址。

var p *int
i := 42
p = &i
与 C 不同,Go 没有指针运算。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i

9. 结构体

9.1

type Vertex struct {X intY int
}
v := Vertex{1, 2}
v.X = 4

9.2 结构体指针

 v := Vertex{1, 2}p := &vp.X = 1e9

可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以。
9.3 结构体文法

v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
v3 = Vertex{}      // X:0 Y:0
p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)

10. 数组

var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)

11. 切片

10.1 每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。

a[low : high]

它会选择一个半开区间,包括第一个元素,但排除最后一个元素。
10.2 切片就像数组的引用,切片并不存储任何数据,它只是描述了底层数组中的一段。更改切片的元素会修改其底层数组中对应的元素。
10.3 下面这样则会创建一个和上面相同的数组,然后构建一个引用了它的切片:

[]bool{true, true, false}

10.4 切片下界的默认值为 0,上界则是该切片的长度。
10.5 切片的长度就是它所包含的元素个数。切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。
10.6 切片的零值是 nil。if s == nil
10.7 make 函数会分配一个元素为零值的数组并返回一个引用了它的切片:

a := make([]int, 5)  // len(a)=5
b := make([]int, 0, 5) // len(b)=0, cap(b)=5

10.8 切片可包含任何类型,甚至包括其它的切片。
10.9 append 的结果是一个包含原切片所有元素加上新添加元素的切片。当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。返回的切片会指向这个新分配的数组。

12. Range

10.1 for 循环的 range 形式可遍历切片或映射。
当使用 for 循环遍历切片时,每次迭代都会返回两个值。第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。

for i, v := range pow {fmt.Printf("2**%d = %d\n", i, v)}

12.2 可以将下标或值赋予 _ 来忽略它。

for i, _ := range pow
for _, value := range pow

若你只需要索引,忽略第二个变量即可。

for i := range pow

13. 映射

13.1 映射将键映射到值。
映射的零值为 nil 。nil 映射既没有键,也不能添加键。
make 函数会返回给定类型的映射,并将其初始化备用。

var m map[string]Vertex
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{40.68433, -74.39967,
}

13.2

var m = map[string]Vertex{"Bell Labs": Vertex{40.68433, -74.39967,},"Google": Vertex{37.42202, -122.08408,},
}

13.3

var m = map[string]Vertex{"Bell Labs": {40.68433, -74.39967},"Google":    {37.42202, -122.08408},
}

13.4

m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)

#14. 函数值
14.1 函数也是值。它们可以像其它值一样传递。
函数值可以用作函数的参数或返回值。

hypot := func(x, y float64) float64 {return math.Sqrt(xx + yy)
}
fmt.Println(hypot(5, 12))

14.2 Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值,换句话说,该函数被这些变量绑定在一起。

15.方法

15.1

type Vertex struct {X, Y float64
}
func (v Vertex) Abs() float64 {return math.Sqrt(v.Xv.X + v.Yv.Y)
}
func main() {v := Vertex{3, 4}fmt.Println(v.Abs())
}

可以为非结构体类型声明方法。接收者的类型定义和方法声明必须在同一包内;不能为内建类型声明方法。

type MyFloat float64
func (f MyFloat) Abs() float64 {if f < 0 {return float64(-f)}return float64(f)
}
func main() {f := MyFloat(-math.Sqrt2)fmt.Println(f.Abs())
}

15.2. 指针接收者
指针接收者的方法可以修改接收者指向的值(就像 Scale 在这做的)。由于方法经常需要修改它的接收者,指针接收者比值接收者更常用。
若使用值接收者,那么 Scale 方法会对原始 Vertex 值的副本进行操作。

func (v *Vertex) Scale(f float64) {v.X = v.X * fv.Y = v.Y * f
}

15.3 指针重定向
比较前两个程序,你大概会注意到带指针参数的函数必须接受一个指针:

var v Vertex
ScaleFunc(v, 5)  // 编译错误!
ScaleFunc(&v, 5) // OK

而以指针为接收者的方法被调用时,接收者既能为值又能为指针:

var v Vertex
v.Scale(5)  // OK
p := &v
p.Scale(10) // OK

由于 Scale 方法有一个指针接收者,为方便起见,Go 会将语句 v.Scale(5) 解释为 (&v).Scale(5)。
接受一个值作为参数的函数必须接受一个指定类型的值:

var v Vertex
fmt.Println(AbsFunc(v))  // OK
fmt.Println(AbsFunc(&v)) // 编译错误!

而以值为接收者的方法被调用时,接收者既能为值又能为指针:

var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK

这种情况下,方法调用 p.Abs() 会被解释为 (*p).Abs()。
使用指针接收者的原因有二:
首先,方法能够修改其接收者指向的值。
其次,这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效。

16. 接口

16.1 接口类型 是由一组方法签名定义的集合。
接口类型的变量可以保存任何实现了这些方法的值。
由于 Abs 方法只为 *Vertex (指针类型)定义,因此 Vertex(值类型)并未实现 Abser。

type Abser interface {Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 {if f < 0 {return float64(-f)}return float64(f)
}

16.2 隐式实现
类型通过实现一个接口的所有方法来实现该接口。既然无需专门显式声明,也就没有ldquo;implementsrdquo;关键字。
隐式接口从接口的实现中解耦了定义,这样接口的实现可以出现在任何包中,无需提前准备。
16.3 接口值
接口也是值。它们可以像其它值一样传递。
接口值可以用作函数的参数或返回值。
在内部,接口值可以看做包含值和具体类型的元组:
(value, type)

func describe(i I) {fmt.Printf("(%v, %T)\n", i, i)
}

16.4

16.5 底层值为 nil 的接口值
即便接口内的具体值为 nil,方法仍然会被 nil 接收者调用。

func (t *T) M() {if t == nil {fmt.Println("<nil>")return}fmt.Println(t.S)
}
var t *T
i = t
describe(i)
i.M()

16.6 nil 接口值
nil 接口值既不保存值也不保存具体类型。

type I interface {M()
}
func main() {var i Idescribe(i)i.M()
}

16.7 空接口
指定了零个方法的接口值被称为 空接口:
interface{}
空接口可保存任何类型的值。(因为每个类型都至少实现了零个方法。)
空接口被用来处理未知类型的值。例如,fmt.Print 可接受类型为 interface{} 的任意数量的参数。

func main() {var i interface{}describe(i)i = 42describe(i)i = "hello"describe(i)
}

16.8 类型断言
类型断言 提供了访问接口值底层具体值的方式。

t := i.(T)

该语句断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t。
若 i 并未保存 T 类型的值,该语句就会触发一个恐慌。
为了 判断 一个接口值是否保存了一个特定的类型,类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。

t, ok := i.(T)
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // 报错(panic)
fmt.Println(f)

16.9 类型选择
类型选择 是一种按顺序从几个类型断言中选择分支的结构。
类型选择与一般的 switch 语句相似,不过类型选择中的 case 为类型(而非值), 它们针对给定接口值所存储的值的类型进行比较。

func do(i interface{}) {switch v := i.(type) {case int:fmt.Printf("Twice %v is %v\n", v, v*2)case string:fmt.Printf("%q is %v bytes long\n", v, len(v))default:fmt.Printf("I don't know about type %T!\n", v)}
}

17. Stringer

fmt 包中定义的 Stringer 是最普遍的接口之一。

type Stringer interface {String() string
}
func (p Person) String() string {return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}

18. 错误

19. Reader

r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {n, err := r.Read(b)fmt.Printf("n = %v err = %v b = %v\n", n, err, b)fmt.Printf("b[:n] = %q\n", b[:n])if err == io.EOF {break}
}

19. Go 程

Go 程(goroutine)是由 Go 运行时管理的轻量级线程。

go f(x, y, z)

会启动一个新的 Go 程并执行f(x, y, z)
f, x, y 和 z 的求值发生在当前的 Go 程中,而 f 的执行发生在新的 Go 程中。

20. 信道

信道是带有类型的管道,你可以通过它用信道操作符 <- 来发送或者接收值。

ch <- v    // 将 v 发送至信道 ch。
v := <-ch  // 从 ch 接收值并赋予 v。

(箭头就是数据流的方向。)
和映射与切片一样,信道在使用前必须创建:

ch := make(chan int)

默认情况下,发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。

带缓冲的信道
信道可以是 带缓冲的。将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道:

ch := make(chan int, 100)

range 和 close
发送者可通过 close 关闭一个信道来表示没有需要发送的值了。接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完

v, ok := <-ch

之后 ok 会被设置为 false。
循环 for i := range c 会不断从信道接收值,直到它被关闭。注意: 只有发送者才能关闭信道,而接收者不能。向一个已经关闭的信道发送数据会引发程序恐慌(panic)。

20. select 语句

select 语句使一个 Go 程可以等待多个通信操作。
select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。

默认选择
当 select 中的其它分支都没有准备好时,default 分支就会执行。
为了在尝试发送或者接收时不发生阻塞,可使用 default 分支:

select {case i := <-c:// 使用 i
default:// 从 c 中接收会阻塞时执行
}

21. sync.Mutex

互斥(mutualexclusion)* ,我们通常使用 互斥锁(Mutex) 这一数据结构来提供这种机制。
Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:

Lock
Unlock

我们可以通过在代码前调用 Lock 方法,在代码后调用 Unlock 方法来保证一段代码的互斥执行。参见 Inc 方法。
我们也可以用 defer 语句来保证互斥锁一定会被解锁。参见 Value 方法。

【Go】超详细Go入门相关推荐

  1. 超强、超详细Redis入门教程【转】

    这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使用r ...

  2. 超详细Redis入门教程——Redis命令(下)

    前言 本文小新为大家带来 超详细Redis入门教程--Redis命令 相关知识,具体内容包括简单动态字符串 SDS,集合的底层实现原理,BitMap 操作命令,HyperLogLog 操作命令,Geo ...

  3. 超详细Redis入门教程——Redis命令(上)

    前言 本文小新为大家带来 超详细Redis入门教程--Redis命令(上) 相关知识,具体内容包括Redis 基本命令,Key 操作命令,String 型 Value 操作命令,Hash 型 Valu ...

  4. 超详细Redis入门教程——Redis概述

    前言 本文小新为大家带来 超详细Redis入门教程--Redis概述 相关知识,具体内容包括Redis简介,Redis的用途,Redis的特性,Redis的IO模型(包括:单线程模型,混合线程模型,多 ...

  5. 超详细Redis入门教程——Redis 的安装与配置

    前言 本文小新为大家带来 超详细Redis入门教程--Redis 的安装与配置 相关知识,具体内容包括Redis 的安装,连接前的配置,Redis 客户端分类(包括:命令行客户端,图形界面客户端,Ja ...

  6. ECharts实现数据可视化超详细基础入门教程

    ECharts实现数据可视化超详细基础入门教程 ECharts介绍 ECharts官网:https://echarts.apache.org/zh/index.html ECharts是一款基于Jav ...

  7. 手把手讲解超详细python入门游戏项目‘打外星飞船’(二)

    手把手讲解超详细python入门游戏项目'打外星飞船'(二) 上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动.射击子弹,但是在此之前我们还有一个非常重要的部分–重构. 重 ...

  8. 手把手讲解超详细python入门游戏项目‘打外星飞船’(四)

    手把手讲解超详细python入门游戏项目'打外星飞船'(四) 在经过创立屏幕.飞船移动和设置子弹,我们这里开始设置外形人的创建和移动.我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两 ...

  9. 手把手讲解超详细python入门游戏项目‘打外星飞船’(五)

    手把手讲解超详细python入门游戏项目'打外星飞船'(五) 这是最后一个项目了,前面我们讲了整个游戏页面的控制.飞船.子弹.外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文 ...

  10. 手把手讲解超详细python入门游戏项目‘打外星飞船’(三)

    手把手讲解超详细python入门游戏项目'打外星飞船'(三) 第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解.因为有很多 ...

最新文章

  1. oracle ddl会被什么阻塞,MySQL Online DDL与DML并发阻塞关系总结
  2. c 定义结构体时提示应输入声明_C语言结构体的坑很多,这6大方法千万要记住!...
  3. Oracle 原理:序列
  4. java(eclipse)和数据库(mysql)的连接
  5. Python人脸识别的简要介绍(附实例、Python代码)
  6. w10安装ubuntu_Windows10安装ubuntu18.04双系统教程
  7. C#曲线分析平台的制作(二,echarts前后台数据显示)
  8. 怎么制作铁闸门_咖啡师养成记 | 教你做一杯合格的拿铁咖啡
  9. 电子工程师常用的单位转换
  10. 树莓派调用百度API实现果蔬识别部署
  11. 基于Python 实现 Spirent TestCenter 自动化
  12. 树莓派控制3631AS数码管 驱动 python程序 共阴数码管|徐奥雯编写|XUAOWEN
  13. 什么是外包公司,外包公司与互联网公司的区别
  14. HarmonyOS开发详解(四)——鸿蒙Page Ability功能及UI界面开发详解
  15. [原创][NOIP2005]篝火晚会(超详细题解,3种思路)
  16. cpm、cpc、cps和cpa分别是什么意思
  17. 史上最全!234个财务数据分析数据指标归纳总结
  18. 2022中国健博会/北京健康产业展/北京艾灸与艾制品展览会
  19. 窥探、窃取、威胁,恶意爬虫正在搞垮你的网站,这届“网络流氓”真不好对付
  20. WebMagic Java爬虫框架初探

热门文章

  1. Windows7更换锁屏壁纸
  2. 安装包 | 工具 | 资料 | 文档
  3. 潮阳实验学校文件服务器,今天,潮阳实验学校发出!
  4. 【神经网络】(12) MobileNetV2 代码复现,网络解析,附Tensorflow完整代码
  5. matlab 互信息计算公式,matlab几种计算互信息的方法
  6. 别一想到搜索就用百度啦,推荐10个常用的垂直搜索引擎
  7. vector 相关应用
  8. windows怎么录制内部发出的声音
  9. 数组的使用示例(老师的任务)
  10. 资本寒冬 瓜子二手车数据动刀“整容”只为傍大款?