Go Lang学习笔记——基础篇

说明:笔记内容参考Go指南

 

目录

一、包、变量和函数

1.运行入口

2.导入路径

3.简单的输出

4.格式化输入输出

5.函数

6.返回值

7.变量申明

8.基本类型

9.零值

10.类型转换

11.常量

二、流程控制语句:for、if、else、swith、defer

for循环

if、else

switch

defer

三、更多类型:struct、slice和映射

指针

结构体

数组

切片

扩展阅读

range

扩展阅读

映射

函数值

函数的闭包(?)

扩展阅读

附录


 

 

一、包、变量和函数

1.运行入口

Go程序由包组成,程序的运行入口是main。

package main

 

2.导入路径

通过圆括号组合导入,即“打包”导入语句,如:

import (
	"fmt"
    "math"
)

同时也可以分组导入(形式上更好)

import "fmt"
import "math"

 

3.简单的输出

如果一个名字以大写字母开头,如Pi,表明它是已导出的,导出自math包

package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.Pi)
}

 

4.格式化输入输出

[布尔]

%t

[整数]

%b 二进制表示

%d 十进制表示

%o 八进制表示

%x 十六进制表示,字母形式为小写 a-f

%X 十六进制表示,字母形式为大写 A-F

%c 相应 Unicode 码点所表示的字符

[字符串与字节切片]

%s 字符串或切片的无解译字节

%q 双引号围绕的字符串,由 Go 语法安全地转义

[指针]

%p

 

5.函数

可以没有参数,也可以接受多个参数

连续多个函数命名形参类型相同时,除最后一个都可以省略

如:

x int, y int

可以所写成

x, y int
func swap(x, y string) (string, string) {
	return y, x
}

func add(x, y int) (int, int, int) {
	return x + y, x, y
}

func main() {
	fmt.Println("Hello World!")
	fmt.Println(add(1, 4))
	fmt.Println(swap("hello", "world"))
}

 

6.返回值

go可返回任意多个返回值

且返回值可以被命名,名称应当具有一定的意义,return可以直接返回已命名的返回值(不适用于长函数,影响代码可读性)

func jisuan(sum int) (x, y int) {
	x = sum*2 + 1
	y = sum - 1
	return
}
func main() {
	fmt.Println(jisuan(5))
}

 

7.变量申明

var定义变量列表

在函数内,可用:=代替var定义

函数外必须以关键字(var、func等)开始

var a, b int = 1, 2

func main() {
	var x, y = "Be", "Happy"
	c := 2 * 2
	fmt.Println(a, b, x, y, c)
}

短变量声明

可以用:=代替var,但:=不能用于函数外

 

8.基本类型

布尔型 bool

字符串类型 string

数字类型

int8 (有符号 8 位整型 (-128 到 127) )

int16 (有符号 16 位整型 (-32768 到 32767) )

int32 (有符号 32 位整型 (-2147483648 到 2147483647) )

int64 (有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) )

unit8 (无符号 8 位整型 (0 到 255) )

unit16(无符号 16 位整型 (0 到 65535) )

unit32(无符号 32 位整型 (0 到 4294967295) )

unit64(无符号 64 位整型 (0 到 18446744073709551615) )

float32 (IEEE-754 32位浮点型数 )

float64 (IEEE-754 64位浮点型数 )

complex64 (32 位实数和虚数 )

complex128 (64 位实数和虚数 )

其他数字类型:

byte (uint8 的别名)

rune (int32 的别名, 表示一个 Unicode 码点)

int 有符号整型32 或 64 位

unit 无符号整型32 或 64 位

unitptr (无符号整型,用于存放一个指针。 uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方 )

派生类型

 

 同导入语句一样, 变量声明也可以“分组”成一个语法块

%T显示类型 %v显示value

 

9.零值

没有明确初始值的变量声明会被赋予它们的零值。

数值型 0;布尔型 false;字符串型 “''(空字符串)

var i int
	var f float32
	var b bool
	var s string
	fmt.Printf("%v, %v, %v, %q\n", i, f, b, s)

注:需要格式化输出信息时用Printf,其他时间可以用Println

 

10.类型转换

表达式 T(v)将值v转换为类型T

与 C 不同的是,Go 在不同类型的项之间赋值时需要显式转换。

 

在声明一个变量而不指定其类型时,变量的类型由右值推导得出

func main() {
	i := 4
	f := 3.14
	c := 0.6 + 5i
	fmt.Printf("%v:%T\n", i, i)
	fmt.Printf("%v:%T\n", f, f)
	fmt.Printf("%v:%T\n", c, c)
}

运行结果

4:int
3.14:float64
(0.6+5i):complex128

 

11.常量

使用 const 关键字 ,可以是字符、字符串、布尔值或数值 ,不能用 := 语法声明

func main() {
	const i = 1
	fmt.Println(i)
	const a = 'a'
	fmt.Printf("%c\t%d\t%v\n", a, a, a)
	const name = "a"
	fmt.Printf("%v\n", name)
}

运行结果

1
a	97	97
a

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

 


 

二、流程控制语句:for、if、else、swith、defer

for循环

for 初始化语句;条件表达式;后置语句{ }

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

其中,初始化语句和后置语句是可选的 ,for ;条件表达式;{ }

var s int = 1
	for ;s < 10; {
		s += s
	}
	fmt.Println(s)

for 条件表达式等价于其他语言中的while

​ (发现一个问题: 在输入语句  for ;s < 10;  运行时会自动变成  for s < 10 )

如果省略循环条件,该循环就不会结束

 

if、else

package main
import "fmt"
func main() {
	for i := 1; i < 10; i++ {
		if i += 1; i%2 == 0 {
			fmt.Println(i)
		}
	}
}

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

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

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
		pow(4, 2, 10),
		pow(2, 3, 20),
	)
}

运行结果

27 >= 20
16 >= 10
9 20 10 8

注意输出的顺序

 

switch

自动提供了 case的 break 语句 ,且case 无需为常量,且取值不必为整数

func main() {
	fmt.Println("put a number:")
	var age int
	//	fmt.Scan(&age)
	fmt.Scanf("%d", &age)
	switch {
	case age < 3:
		fmt.Println("baby")
	case age < 18:
		fmt.Println("student")
	case age > 60:
		fmt.Println("old")
	default:
		fmt.Println("work hard")
	}
}

case 语句从上到下顺次执行,直到匹配成功时停止

没有条件的 switch 同 switch true 一样

 

defer

defer将函数推迟到外层函数返回之后执行

推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用 ,推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用

func main() {
	fmt.Println("counting")
	for i := 0; i < 10; i++ {
		defer fmt.Println(i)
	}
	fmt.Println("done")
}

运行结果

counting
done
9
8
7
6
5
4
3
2
1
0

注意输出的顺序


 

三、更多类型:struct、slice和映射

指针

指针保存了值的内存地址 ,类型 *T 是指向 T 类型值的指针

& 操作符会生成一个指向其操作数的指针

* 操作符表示指针指向的底层值

fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i

与 C 不同,Go 没有指针运算

func main() {
	i := 7
	j := 9
	var p *int
	p = &i //指向i
	fmt.Println(i)
	fmt.Println(*p) //通过指针读i的值
	*p += 1         //通过指针修改i的值
	fmt.Println(i)
	fmt.Println(*p)
	p = &j  //指向j
	*p *= 2 //通过指针修改j的值
	fmt.Println(i)
	fmt.Println(j)
	fmt.Println(*p) //通过指针读j的值
}

运行结果

7
7
8
8
8
18
18

 

结构体

结构体(struct)就是一个字段的集合 ,结构体字段使用点号或结构体指针来访问

func main() {
	v := Vertex{1, 2}
	fmt.Println(v)	//{1 2}
	p := &v
	fmt.Println(*p)	//{1 2}
	p.X = 9
	fmt.Println(p.X)	//9
	fmt.Println(p.Y)	//2
	fmt.Println(v)	//{9 2}
}

结构体文法通过直接列出字段的值来新分配一个结构体

使用 Name: 语法可以仅列出部分字段。(字段名的顺序无关。)

特殊的前缀 & 返回一个指向结构体的指针。

type Vertex struct {
	X, Y int
}
var (
	v1 = Vertex{1, 2}  // has type Vertex
	v2 = Vertex{Y: 9}  // X:0 is implicit
	v3 = Vertex{}      // X:0 and Y:0
	p  = &Vertex{1, 2} // has type *Vertex
)
func main() {
	fmt.Println(v1, v2, v3)	//{1 2} {0 9} {0 0}
	fmt.Println(p)	//&{1 2}
	fmt.Println(*p)	//{1 2}
}

 

数组

类型 [n]T 表示拥有 n 个 T 类型的值的数组

var a [10]int	//变量 a 声明为拥有 10 个整数的数组

 

切片

类型 []T 表示一个元素类型为 T 的切片

a[low : high]	//半开区间,包括第一个元素,但排除最后一个元素 

更改切片的元素会修改其底层数组中对应的元素

t := [5]int{1,3,5,7,9}
	fmt.Println(t)	//[1 3 5 7 9]
	tt := t[1:4]
	fmt.Println(tt)	//[3 5 7]
	tt[2] = 8
	fmt.Println(tt)	//[3 5 8]

切片文法类似于没有长度的数组文法

func main() {
	q := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(q)

	r := []bool{true, false, true, true, false, true}
	fmt.Println(r)

	s := []struct {
		i int
		b bool
	}{
		{2, true},
		{3, false},
		{5, true},
		{7, true},
		{11, false},
		{13, true},
	}
	fmt.Println(s)
}

运行结果

[2 3 5 7 11 13]
[true false true true false true]
[{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]

切片下界的默认值为 0上界则是该切片的长度

	s := []int{2, 3, 5, 7, 11, 13}

	t := s[1:4]
	fmt.Println(t)	//[3 5 7]

	q := s[:2]
	fmt.Println(q)	//[2 3]

	p := s[1:]
	fmt.Println(p)	//[3 5 7 11 13]

切片拥有 长度 和 容量

 len(s)获取长度:它所包含的元素个数

cap(s)获取容量:从它的第一个元素开始数,到其底层数组元素末尾的个数

 

切片的零值是 nil ,nil 切片的长度和容量为 0 且没有底层数组

 

切片可以用内建函数 make 来创建

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

切片可包含任何类型,甚至包括其它的切片

package main

import (
	"fmt"
	"strings"
)

func main() {
	board := [][]string{
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
	}

	board[0][0] = "X"
	board[2][2] = "O"
	board[1][2] = "X"
	board[1][0] = "O"
	board[0][2] = "X"
	
	fmt.Println(board)
	for i := 0; i < len(board); i++ {
		fmt.Printf("%s\n", strings.Join(board[i], " "))
	}
}

运行结果

[[X _ X] [O _ X] [_ _ O]]
X _ X
O _ X
_ _ O

append 函数为切片追加新的元素

扩展阅读

Go 切片:用法和本质

 

range

for 循环的 range 形式可遍历切片或映射

当使用 for 循环遍历切片时,每次迭代都会返回两个值:下标和对应元素

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

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

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

运行结果

2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128
1
2
4
8
16
32
64
128

扩展阅读

Go指南练习之《slice》

 

映射

映射将键映射到值 ,是一种数据结构,用于存储一系列无序的键值对

映射的零值为 nilnil 映射既没有键,也不能添加键。

创建并初始化映射

1、使用内置的make 函数

2、使用映射字面量

//1、使用make声明映射,创建一个映射,键的类型是string,值的类型是int
	d := make(map[string]int)	
	d["a"] = 1
	fmt.Println(d["a"])		//1

	//2、为映射赋值时,{}很重要,没有的话相当于对nil赋值会发生运行错误
	b := map[string]int{}
	b["s"] = 11
	fmt.Println(b["s"])

	//使用两个键值对初始化映射
	c := map[string]int{"z": 9, "y": 10}
	fmt.Println(c)		//map[z:9 y:10]
	
	//从映射取值有两个选择:
	//1.同时获得值,表示键是否存在的标志
	value, exists := c["y"]
	if exists {
		fmt.Println(value)
	}
	//2.只返回键的值

映射文法与结构体相似,不过必须有键名

若顶级类型只是一个类型名,你可以在文法的元素中省略它

type Vertex struct {
	Lat, Long float64
}

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

func main() {
	fmt.Println(m)
}

修改映射

m[key] = elem	//在映射 m 中插入或修改元素 
elem = m[key]	//获取元素
delete(m, key)	//删除元素
elem, ok := m[key]	//通过双赋值检测某个键是否存在
//若key在m中,ok为true;否则,ok为false。
//若key不在映射中,那么elem是该映射元素类型的零值

 

函数值

函数也是值。它们可以像其它值一样传递。

函数值可以用作函数的参数或返回值。

import (
	"fmt"
	"math"
)

func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}

func main() {
	hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
	fmt.Println(hypot(5, 12))	//13

	fmt.Println(compute(hypot))		//5
	fmt.Println(compute(math.Pow))	//3**4=81
}
func f4(fn func(float64, float64) (float64, float64)) (float64, float64) {
	return fn(4, 2)
}

func f3(fn, fm func(int, int) int) int {
	return fn(4, 5) + fm(1, 2)
}

func f2(a, b float64) (float64, float64) {
	return a + b, math.Pow(a, b)
}

func main() {
	f1 := func(x, y int) int {
		return x + y
	}
	fmt.Println(f1(1, 2))	//x + y=3
	fmt.Println(f2(3, 2))	//a + b, math.Pow(a, b)=5 9
	fmt.Println(f3(f1, f1))	//fn(4, 5) + fm(1, 2)=12
	fmt.Println(f4(f2))	//6 16
}

 

函数的闭包(?)

Go 函数可以是一个闭包。

闭包的体现形式,就是用函数返回另一个函数

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos:= adder()
	for i := 0; i < 10; i++ {
		fmt.Println(pos(i))
	}
}

运行结果

0	//sum=0+0
1	//sum=0+1=1
3	//sum=1+2=3
6	//sum=3+3=6
10	//sum=6+6=10
15
21
28
36
45

扩展阅读

【Go学习】理解Go语言中的函数闭包

 

附录

math包

fmt.Println(math.Abs(float64(i))) //绝对值

fmt.Println(math.Ceil(5.0)) //向上取整

fmt.Println(math.Floor(5.8)) //向下取整

fmt.Println(math.Mod(11, 3)) //取余数,同11%3

fmt.Println(math.Modf(5.26)) //取整数,取小数

fmt.Println(math.Pow(3, 2)) //x的y次方

fmt.Println(math.Pow10(4)) // 10的n次方

fmt.Println(math.Sqrt(8)) //开平方

fmt.Println(math.Cbrt(8)) //开立方

fmt.Println(math.Pi)


Go的基础内容差不多就是这些,剩下方法和接口、并发相关的知识,要开始深入了。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故沉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值