Go语言学习笔记

  总结一下初学go语言的笔记,方便复习
  参考书籍:《go语言趣学指南》

1.初识go语言

  使用playground运行代码

  使用main方法标识代码入口

  大括号的唯一位置
    在go中,大括号只有一种放置位置,左大括号与func关键字于同一层,右大括号位于单独一层,否则会报错。

2.常量和变量

  使用const标识常量,使用var标识变量

  变量声明的三种方式

package main

import "fmt"

func main() {

	var a = 111
	var b = 222

	var (
		a = 111
		b = 222
	)

	var a, b = 111, 222    // 三种方式的效果都一样

	fmt.Println(a, b)
}

  var简短声明

	var test = 33
	test := 33
	

  上述两种方式实现的效果完全一样

  +=、++、–等操作符仍然有效

3.分支和循环

  if分支

	test := 100

	if res := -1; test > 99 {  // 在条件中同时使用简短声明
		fmt.Println(res)
	} else if test < 3 {
		fmt.Println("error")
	} else {
		fmt.Println("error")
	}
	

  使用&&表示逻辑与,||表示逻辑或,!表示逻辑非

  switch分支

	test := 100

	switch res := -1; test { // 在这里同时使用简短声明
	case 3:
		fmt.Println("error")
	case 100:
		fmt.Println(101)
		fallthrough
	default:
		fmt.Println(res)
	}
	

  

	test := 100

	switch {
	case test > 99:
		fmt.Println(99)
	case test < -1:
		fmt.Println(101)
		fallthrough
	default:
		fmt.Println("test")
	}

  for循环

	for i := 0; i < 3; i++ { // 使用简短声明
		fmt.Println(i)
	}

	j := 0
	for j < 3 {  //不使用简短声明
		fmt.Println(j)
		j++
	}
	

  上述if、switch、for的条件中均可以使用简短声明,使用分号隔开即可

4.浮点数

  声明类型变量

var 变量名 类型变量 =var test float64 = 39493
test := 39493
var test float32 = 39493
test := 39493

  也可以不声明类型变量,默认为float64类型,go中大部分浮点数都是float64

  浮点数进行比较时需要注意,精度不能太高,否则会出错。

5.整数

  Go提供了10种整数类型可供选择,默认为int类型,其他可选的还有uint、int8、int64等类型
  int和uint没有指定位数,它们根据硬件的架构来决定(32位架构就是32位,64位架构它们就是64位)。
  如果数值过大,且想要整数不会随着硬件变化,就要指定相应的位数int32、int64等。

  通常使用big包和const存储异常大的整数

6.类型转换

  使用新类型同名的函数来包裹变量即可

package main

import "fmt"

func main() {
	a := 41
	fmt.Println("%T \n", a)
	b := float64(a)
	fmt.Printf("%T", b)
}

7.函数

  在go中,以大写字母开头(类似于public)的函数、变量以及其他标识符是对其他包可用的,反之则不然。
  函数声明

func 函数名(形参名 类型, 形参名 类型, ···) (返回值类型,返回值类型) {
	行为
}

eg:
func test(a int, b float64) int {
	行为
}

func test(a int64) (float32, int16) {
	行为
}

8.方法

  声明新的类型

type 新类型 基于的类型

type myInt int32
var a myInt = 22
fmt.Printf("%T", a)

  注意:声明的新类型和基于的类型不是同一个类型,不能直接运算

  我们可以为自己声明的类型添加方法
  方法声明如下

关键字 接收者 方法名 返回值 {    // 接收者有且只有一个,它的格式如下
	行为                     // (接收者变量名 自己声明的类型)
}
eg:
func (a myInt) test() myInt {
	return a += 1
}

  使用的时候直接用对应类型的变量调用即可

9.函数

  包括高阶函数、匿名函数等,现在用不到,略。

10.数组

  数组初始化

var test = [3]string{"test1", "test2", "test3"}

test := [3]string{"test1", "test2", "test3"}

test := [...]string{"test1", "test2"}  // go编译器会自动计算数组元素的数量

test := []string{"test1", "test2"} // 这种方式利用的是数组切片,先在内部创建对应的数组
 				                   // 再返回的是对应数组的切片(视图)
 				                   

  迭代数组,使用range关键字可以取得数组中每个元素的索引和值

  数组复制—无论是将数组赋值给新的变量还是将它传递给函数,都会产生一个完整的数组副本

  数组切片—形式和python完全一样,切片后返回的数组提供的是原数组的视图,改变切片中元素的值同样会影响到原数组。

  数组也有对应的方法

  第十八章 数组切片的扩展,现在应该用不上,略。

11.映射

  映射声明

map[key类型] value类型 {
	key1: value1,
	key2: value2,    // 注意,这里的逗号也是必须的(很奇怪)
}

12.结构

  结构声明

var 结构名 struct {
	属性 类型
	属性 类型
	···
}

// 也可以通过自定义的类型来复用结构
type 类型名 struct {
	属性 类型
	属性 类型
	···
}

  结构初始化

变量名 := 类型(基于结构){属性: 值, 属性: 值}
eg:
type test struct {
	key1 int
	key2 int
}

t := test{key1: 2, key2: 5}

  结构的赋值将产生相应的副本

  由结构组成的切片

变量名 := []类型(基于结构){
	{key1: value1, ···}
	{key2: value2, ···}
	···
}

  构造函数,名称为newTypeName/NewTypeName的函数,感觉不是很有用,就是一个普通的函数,只是名称有所规范,略。

  Go没有提供class,而是通过结构方法来满足相同的需求。

13.转发

  在结构里面还可以嵌套其他结构/类型,这些结构/类型有自己的方法,我们可以通过转发的方式使得顶层结构使用其内部结构/类型的方法,具体声明如下

package main

import "fmt"

type struct1 struct {
	age int
}

func (s struct1) addOne() int { // 这种方式改变不了对应属性的值
	s.age += 1 // 要使用指针的方式
	return s.age
}

func main() {
	type topStruct1 struct {
		struct1 struct1 // 第一个struct1是属性名,第二个是它的类型
		id      int
	}

	type topStruct2 struct {
		struct1 // 不给定属性名,直接指定类型
		id      int
	}

	t1 := topStruct1{
		struct1: struct1{age: 23},
		id:      55,
	}

	t2 := topStruct2{
		struct1: struct1{age: 25},
		id:      66,
	}

	fmt.Println(t2.addOne(), t2.age) // 打印26 25 可以直接使用嵌套类型的方法和属性
	fmt.Println(t1.id)               // 打印55

}

  但转发的方法存在同名的情况,这个时候我们为顶层结构定义一个同名的新方法即可解决问题。

14.接口

  只要满足了接口所声明的方法,任何自定义类型/结构的任何值都可以被归类到相应的接口中(按照惯例,接口类型的名称通常以er为后缀)

package main

import "fmt"

type nothing float64

func (t nothing) test() int {
	return int(t)
}

func main() {

	type tester interface {
		test() int // 对应的方法名 返回值类型
	}

	// var t tester = nothing(32.0)

	var n nothing = 32.0
	var t tester = n

	fmt.Println(t.test())

}

  接口有点绕,但也很重要,还需要进一步探索

15.指针

  使用&操作符获得指定变量的内存地址
  使用获得内存地址指向的值(与&操作相反)
  将放在类型前面表示要声明指针类型,将它放在变量前面则是要取该地址存储的值

package main

import "fmt"

func main() {

	test := 2333

	var address = &test
	fmt.Println(address)
	fmt.Println(*address)

	var t *int = address
	fmt.Println(t)
	fmt.Println(*t)
}

  在复合变量(结构/数组)前面可以直接放置&操作符
  使用的使用不用加*号,go语言自动为它们解析

package main

import "fmt"

func main() {

	type test struct {
		age int
	}

	t := &test{age: 3}

	fmt.Println(t.age) // 使用的时候不用加*号,直接引用即可

	nums := &[...]int{1, 3, 7}

	fmt.Println(nums[2])  // 和其他语言的方式一样
}


  同样的,我们可以使用指针作为方法的接收者,这样可以对结构/数组的属性进行修改,略。

16.nil

  nil空指针的问题,有点深入了,略。

17.异常处理

  Go语言允许函数和方法返回多个值,按照惯例,使用最后一个返回值来表示错误。我们在使用函数/方法执行的结果前,应该先检查是否有错误信息。
  defer关键字—defer可以延迟任何函数/方法,Go语言将保证这些被延迟的操作将在函数return之前执行。

18.协程(goroutine)


  没怎么看懂,待续···

安装和配置go环境

  参考链接:VS code golang开发环境搭建(Windows系统下 )
  GOBIN—目前理解应该是Go编译器所在的位置,基本用不上;
  GOPATH—Go开发时的项目路径,各种包都在这里,类似于Global Environment;

  按照grpc-go官网的教程,安装protoc和两个插件

$ go install google.golang.org/protobuf/cmd/[email protected]
$ go install google.golang.org/grpc/cmd/[email protected]

  如果安装出现问题就直接下载protobuf和grpc项目代码到本地,使用go build命令生成两个可执行文件放到GOBIN的bin目录下即可
Go语言学习笔记_第1张图片



To be a sailor of the world bound for all ports.

你可能感兴趣的:(学习,学习,大数据,golang)