go开发学习笔记——02

一、参考

1. 菜鸟教程

2. 官方文档

3. go社区

4. go开发相关的一堆文档

二、基础语法

(一)行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成
如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

(二)注释

注释和Java的一致。注释规范(可以使用01笔记的注释工具控制)

  • 单行 //
  • 多行 /**/
// 单行

/**
* 多行
**/

(三)命名规范(* 影响封装性)

1、go默认命名规则

Go在命名时以字母a到Z或a到Z或下划线开头,后面跟着零或更多的字母、下划线和数字(0到9)。Go不允许在命名时中使用@、$和%等标点符号。Go是一种区分大小写的编程语言。因此,Manpower和manpower是两个不同的命名。

  1. 当命名(包括常量、变量、类型、函数名、结构字段等)以大写字母开头,如:Name,这种以大写开头的命名形式,在go中默认是可以被其他包使用的(在java中是public的)
  2. 小写就是对其他包不可见的,go默认将小写开头的变量、函数等默认为私有的,只能自己使用(对应java中的private)

2、包命名规则

.go文件 一般在哪个文件夹包名就叫什么,有mian函数的包名一定是main(使用小写,不要包含下划线)。

3、文件命名

.go文件 小写单词,并使用下划线分割单词。

4、结构体

使用驼峰命名法,根据封装类型选择首字母大写,还是小写。

5、接口

与结构体一致,当接口是当函数接口时,命名一般以er结尾

type Reader interface {
	read(id int) int
}

6、变量命名规则

同样使用驼峰命名,根据封装需求,决定第一个字母大小写。

布尔类型,一般以Has、Is,Can等开头。

7、常量命名规则

全大写,以下划线分割单词

(四)关键词

25 个关键字或保留字

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

Go 语言还有 36 个预定义标识符:

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

(五)变量声明

//声明单个
var identifier type = 初始值
//声明多个
var a1 , a2 type = 初始值1, 初始值2

方式一:指定变量类型,如果没有初始化,则变量默认为零值。(跟java类似,直接指出变量类型)

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
//输出
0 0 false ""

方式二:根据值自行判定变量类型。(跟js一致,由值决定变量类型)

package main

import "fmt"

func main() {
	var name = "李华"
	var age = 19
	var sex = true

	fmt.Println(name)
	fmt.Println(age)
	fmt.Println(sex)
}
//输出
李华
19
true

方式三:声明变量的同时赋予初始值,并且这个方式只能在函数(方法)中使用

package main

import "fmt"

func main() {
	score := 98
	name := "lihua"
	fmt.Println(name)
	fmt.Println(score)

}
//输出
lihua
98

score := 98 等价于 var score int score = 98

注意:以下写法是错误的
在这里插入图片描述

":="是用来声明和初始化变量的,赋值操作请使用"="

(六)多变量声明

package main

var x, y int
var (  // 这种因式分解关键字的写法一般用于声明全局变量
	a int
	b bool
)

var c, d int = 1, 2
var e, f = 123, "hello"

//这种不带声明格式的只能在函数体中出现
//g, h := 123, "hello"

func main(){
	g, h := 123, "hello"
	println(x, y, a, b, c, d, e, f, g, h)
}
//输出
0 0 0 false 1 2 123 hello 123 hello

(七)常量

常量使用关键字 const 修饰

package main

const MAX = 16

func main(){
	println(MAX)
}

输出16

常量也可以用作枚举

package main

const (
	Red = 0
	Green = 1
	Blue = 2
)
func main(){
	println(Red)
	println(Green)
	println(Blue)
	println(Blue==2)
}
//输出
0
1
2
true

iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

(八)运算符

go 运算符与java基本一致

算数运算符

运算符描述实例
+相加 A + B 输出结果 30
-相减 A - B 输出结果 -10
*相乘 A * B 输出结果 200
/相除 B / A 输出结果 2
%求余 B % A 输出结果 0
++自增 A++ 输出结果 11
--自减 A-- 输出结果 9

关系运算符

运算符描述实例
== 检查两个值是否相等,如果相等返回 True 否则返回 False。 (A == B) 为 False
!= 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 (A != B) 为 True
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。 (A > B) 为 False
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。 (A < B) 为 True
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 (A >= B) 为 False
<= 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 (A <= B) 为 True

逻辑运算符

运算符描述实例
&& 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 (A && B) 为 False
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 (A || B) 为 True
!逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 !(A && B) 为 True

(九)go的数据类型

序号类型和描述
1布尔型
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
2数字类型
整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
3字符串类型:
字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
4派生类型:
包括:
  • (a) 指针类型(Pointer)
  • (b) 数组类型
  • (c) 结构化类型(struct)
  • (d) Channel 类型
  • (e) 函数类型
  • (f) 切片类型
  • (g) 接口类型(interface)
  • (h) Map 类型
序号类型和描述
1uint8
无符号 8 位整型 (0 到 255)
2uint16
无符号 16 位整型 (0 到 65535)
3uint32
无符号 32 位整型 (0 到 4294967295)
4uint64
无符号 64 位整型 (0 到 18446744073709551615)
5int8
有符号 8 位整型 (-128 到 127)
6int16
有符号 16 位整型 (-32768 到 32767)
7int32
有符号 32 位整型 (-2147483648 到 2147483647)
8int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
序号类型和描述
1float32
IEEE-754 32位浮点型数
2float64
IEEE-754 64位浮点型数
3complex64
32 位实数和虚数
4complex128
64 位实数和虚数
序号类型和描述
1byte
类似 uint8
2rune
类似 int32
3uint
32 或 64 位
4int
与 uint 一样大小
5uintptr
无符号整型,用于存放一个指针

表格来自菜鸟教程

注意:

func main() {
	var a1 int64 = 1
	//注意 int 的大小取决于本计算机(运行代码的机器是32位,还是64位)
	var a2 int = 2
	//调用公共函数Printf,通过%T能判断变量的数据类型
	fmt.Printf("%T,%T",a1,a2)
}

在这里插入图片描述

三、条件分支

if else

package main


func main(){

	high := 10
	width:=20
	println(high*width)
	println((high+width)*2)
	if high>width {
		println((high-width)*2)
	}else {
		println("高小于宽")
	}

}
//输出
200
60
高小于宽

switch

switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。匹配成功后就不会执行其他 case。如果我们需要执行后面的 case,可以使用 fallthrough 。加了fallthrough后,无论下一条case的判断是否成立(为true)都会执行

select

select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。

四、循环

package main

func main() {

	//方式一
	num := 0
	for i := 0; i < 10; i++ {
		num = num + i
	}
	println(num)

	//方式二 等价于while
	i := 0
	for i < 10 {
		i++
		println(i)
	}

	//方式三,for each(增强for循环)
	var n [10]int
	for i := 0; i <10 ; i++ {
		n[i] = i
	}
	for i2 := range n {
		println(i2)
	}

}

五、函数(方法)

go注释规范

注意:如果安装了Goanno 插件。可以直接通过快捷键生成标准注释。

//
//  max
//  @Description:获取最大值
//  @param p1
//  @param p2
//  @return int 返回最大值
func max(p1 int, p2 int) int {

	if p1>p2 {
		return p1
	}
	return p2
}

go支持多返回值,如下:

package main

func main() {
	//直接打印值
	println(square(4, 2))
	//使用变量接收返回值
	var squaresSum ,squaresDifference = square(4, 2)
	println("平方和",squaresSum)
	println("平方差",squaresDifference)
}
//
//  square
//  @Description: 根据传入的参数,计算他们的平方和,平方差
//  @param a
//  @param b
//  @return int
//  @return int
//
func square(a, b int) (int, int) {
	return (a * a) + (b * b), (a * a) - (b * b)
}

六、函数传值和传引用

(一)传递值

传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数


package main

func main() {
	var a1 = 10
	//值传递
	test1(a1)
	println(a1)
}

//
//  test1
//  @Description: 传值测试
//  @param value
//  @return int
//
func test1(value int) int {
	 value = value + 1
	return value
}

输出

10

(二)引用传递

引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
引用传递指针参数传递到函数内,以下是交换函数 swap() 使用了引用传递:

package main

func main() {
	var a1 = 10
	//引用(指针)传递
	test2(&a1)
	println(a1)
}

//
//  test2
//  @Description: 传递引用类型(指针)
//  @param value
//  @return int
//
func test2(value *int) int {
	var tmp = &value
	println(tmp)
	*value = *value+1;
	return 0
}

输出

0xc000055f68
11
// & 号是获取地址的
// * 号是获取值的
// *tpye(*int) 是声明指针类型的,指针类型初始值为nil(空,没有指向任何存储空间)

七、传递函数类型的参数(函数式编程,回调函数)

一个简单的例子

package main

// 声明一个函数类型,在java中就是一个待实现的方法。
//作用是获取函数传入的参数的值
type getValue func(int) int

func main() {
	//方式一:直接传入匿名的函数,(也就是没有名字的函数,只能用一次)。跟java里面的匿名子类差不多,比如线程中的Runnable接口里面的run方法(也叫做单方法接口)
	testCallBack(2, func(x int) int {
		//函数体的具体逻辑
		println("函数真正执行一些业务,(在这里的业务是直接返回传入的参数x的值)")
		return x
	})
	
	//方式二:传入一个具体的函数,这个具体的函数的类型必须与声明的一致(传入的参数是int类型,返回值也是int类型 )
	testCallBack(1, callBack)
}

//
//  testCallBack
//  @Description: 函数式编程,参数是一个函数类型(将函数当作参数传入函数中,在回调(发布-订阅模式)用得比较多)
//  @param x 一个整形参数
//  @param f 一个函数体
//
func testCallBack(x int, f getValue) {
	//上面传入了一个函数。我们在这个方法中(在合适的时候)可以调用这个函数。
	println("一些其他业务")
	//调用传入的函数,函数的声明在开头,也就是getValue func(int) int
	v := f(x)
	println(v)
}

func callBack(x int) int {
	println("方式二,我是一个有名字(名字为:callBack)的回调函数。")
	return x
}

debug分析一下回调函数的运行逻辑(体验函数式编程)
在这里插入图片描述

八、变量作用域(全局变量和局部)

变量作用域和java一致
Go 语言中变量可以在三个地方声明:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

Go 语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑(就近原则

九、数组

一个冒泡排序的例子

// Package main
// @Description: 数组练习
package main

func main() {
	//创建数组的方式
	//方式一
	var array1 = []int{6, 2, 13, 4, 28}
	//方式二
	//array2 :=  [3]int{1, 2, 3}
	//方式三,如果不想数{}号有几个元素,可以用 ... 表示。编译器会根据元素个数自行推断数组的长度
	//var array3 = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

	//迭代遍历,i为数组下标,i2为下标对应的值
	for i, i2 := range array1 {
		println(i)
		println(i2)
	}
	//寻常遍历
	println("---")
	for i := 0; i < len(array1); i++ {
		println(array1[i])
	}

	sort(array1)
	for i := range array1 {
		println(array1[i])
	}
}

//
//  sort
//  @Description: 排序 注意传递数组类型的参数时。数组的大小与传递的大小必须一致
// (比如 传递的参数为:var array1 = [3]int{6, 2, 13, 4, 28} ,那么函数声明也为func sort(array [3]int),
//  如果为动态数组 var array1 = []int{6, 2, 13, 4, 28},那么声明为func sort(array []int),数组大小保存一致,也就是中括号保存一致)
//  @param array
//
func sort(array []int) {
	for i := 0; i < len(array)-1; i++ {
		tag := false
		for j := 0; j < len(array)-1-i; j++ {
			if array[j] > array[j+1] {
				swap(&array[j],&array[j+1])
				//标志是否发生交换
				tag = true
			}
		}
		//一趟下来没有发生交换
		if !tag {
			break
		}
	}
}

//
//  swap
//  @Description: 交换两个值
//  @param p1
//  @param p2
//
func swap(p1 *int, p2 *int) {
	tmp := 0
	tmp = *p1
	*p1 = *p2
	*p2 = tmp
}

二维数组

package main

func main() {
	//二维数组
	var arrayTwo = [][]int{}
	row1 := []int{1, 2, 3}
	row2 := []int{4, 5, 6}
	arrayTwo = append(arrayTwo, row1)
	arrayTwo = append(arrayTwo, row2)
	println(arrayTwo[0][0])
}

切片
使用 [start-index : end-index] 可以将原数组进行切片,同时可以赋值给新变量(注意:新变量元素指向的地址是原数组的地址。)
start-index: 从0开始
end-index: 不包括 end-index
比如 [0:2] 表示获取下标为 0、1的元素。

注意:如果不指定start-index和end-index的值,那么代表获取整个数组。

package main

func main() {
	//切片
	var array = []string{"北京","上海","深圳","广州"}

	array1 := array[0:1]
	for i := range array1 {
		//改变新变量的元素的值
		array1[i] = "**"
	}
	//注意:这里的切片后赋予的变量array1指向的地址还是原数组的地址。
	for i := range array {
		//改变新变量元素的值后,原数组的值也发生了改变
		println(array[i])
	}

}

切片后生成新的数组(新数组的值改变不影响旧数组)
仅仅是切片,切片后的数组的元素指向的地址还是旧数组的地址。为了避免这种情况,可以使用copy函数将切片完全拷贝到新数组中(深拷贝)

package main

func main() {
	//切片
	var array = []string{"北京","上海","深圳","广州"}
	//深拷贝
	var array2 = make([]string,len(array))
	copy(array2,array)
	//改变新数组元素的值,不影响旧数组
	array2[0] = "88"
	for i := range array2 {
		println(array2[i])
	}
	//遍历旧数组
	for i := range array {
		println(array[i])
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值