Go学习记录

Go语言学习笔记


1.写一个简单的Go程序并运行

编写简单的hello.go文件

package main

import "fmt"

func main(){
	fmt.Println("Hello World!")
}

使用go run hello.go运行

或者使用go build命令生成二进制文件并运行

go build hello.go
./hello.exe

对上述代码hello.go语言结构进行分析:

1.package main定义的是包名,必须再源文件的非注释第一行指明属于哪个包。package main表示这是一个可独立运行的程序,每个Go应用程序都应该包含一个名为main的包。

2.import "fmt"表示这个程序需要使用fmt包,fmt中包含了格式化I/O的函数。

3.func main()是程序开始执行的函数,是每个可执行函数必须包含的。

4.fmt.Println()是输出控制,并且自动换行。

5.当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

2.Go基础语法

注释

如C/C++相同单行注释使用//即可,多行注释使用/* */

变量(标识符)

Go中使用字母及符号或数字组成标识符,且标识符的开头只能以字母和下划线构成,不可以数字开头。
无效的标识符:case(关键字)、1ab(违背规则)、a+b(运算符不被允许)

定义变量的方式:

var a int = 1 
//同 a :=1  :=相当于声明 因此之前a不应该被声明
var b string = "test"
var c = "%d&%s"
var d = fmt.Sprintf(c,a,b)//格式化字符串
fmt.Println(d)//1&test

//同时定义多个变量
var a,b int  //未初始化的值为0 bool为false
var a,b int = 1,2

//同时声明多个不同类型变量 一般
var(
	name1 type1,
	name2 type2
)
a,b,c := "123",1,false //自动进行类型推导

常量

Go中,常量即表示无法修改,通过const定义

显式定义:const a int = 123
隐式定义: const a =123

多个相同类型可简写为:
const a, b = 1, 2

const枚举:
const(
	a = "123"
	b = len(a)
	c = unsafe.Sizeof(a)
)

itoa 特殊的常量,可认为是能被编译器修改的常量

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

const (
    a = iota  //0
	b = iota  //1  同样可直接简写为 b 即可
	c = iota  //2
)

const (
    a = iota   //0
    b          //1
    c          //2
    d = "ha"   //独立值,iota += 1
    e          //"ha"   iota += 1
    f = 100    //iota +=1
    g          //100  iota +=1
    h = iota   //7,恢复计数
    i          //8
)

如果当前常量未进行赋值,则其值默认为上一个常量的值;若上一个常量为iota,则当前表示为iota+1。

字符串连接

同Java相同,可使用+对字符串进行连接

fmt.Println("Google" + "Runoob")

格式化字符串

使用fmt.Sprintf格式化字符串,并且赋值给新串

func main() {
    // %d 表示整型数字,%s 表示字符串
    var stockcode=123
    var enddate="2020-12-31"
    var url="Code=%d&endDate=%s"
    var target_url=fmt.Sprintf(url,stockcode,enddate)
    fmt.Println(target_url)
}

声明未被使用

当在局部声明变量a且赋值后,如果不使用a,就会得到a declared and not used错误,即必须被使用,但是全局变量是被允许的

3.Go基础数据类型

布尔型

布尔类型的值只能是 true 或 false ,例如 var a bool = true

数字型

数字型分为整型int与浮点型float32,float64。
int有以下不同类型:

int     -2^31~2^31-1
int8    -2^7~2^7-1
uint8   0~2^8
int16   -2^15~2^15-1
uint16  0~2^16
int32   -2^31~2^31-1
int64   -2^63~2^63-1

Go语言支持复数类型,即complex64(32位实数和虚数)和complex128(64位实数和虚数)

其他数字类型:
byte
rune
uint
int
uintptr

字符串型

字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。

4.Go运算符类型

同C++运算符使用方法基本相同,包含算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符。

且Go中同C++一样支持&和*

运算符优先级 由高到低排列:

1.* / % << >> & &^

2.+ - | ^

3.== != < <= > >=

4.&&

5.||

5.Go条件、循环语句

条件语句

1.if 判断,若为真 则执行下面的内容

2.if else 多个判断条件依次执行,选择执行一个

3.switch 根据不同条件执行不同动作

注意: Go中无C++类似的三目运算符?:

循环语句

列举三种不同的for使用方法:

//1.for init; condition; post {}
for i := 1; i <= 10; i++ {
	a += i
}

//2.for condition {}
for true {//无限循环
}

//3.for { }

其中,init一般为赋值表达式,给变量赋初值,condition关系表达式,控制循环条件,post一般用于对循环变量进行自增/减。

6.Go数组

数组中的索引下标从0开始,地址位置连续。

声明数组

var array_name [size] array_type

//具体样例:
var a [100] int //定义整形数组a,长度为100

初始化数组

var a = [100] int{1,2,3}//后面的值默认为0 
a := [100] int{1,2,3}//同上

若长度不确定可使用...代替,且长度之后不会发生变化
a := [...] int{1,2,3}
但此时不能访问长度外的索引下标
a[3] = 1 //错误

创建二维数组

var array_name [x][y] array_type

//将一维数组添加到二维数组
a := [][] int {}
var b = [3]int{1,2,3}
var c = [3]int{1,2,3}
a = append(a,b)
a = append(a,c)

初始化二维数组

a := [2][3] int {
	{1,2,3},
	{4,5,6},
}
//上面第三行的,为必须存在,若将最后一行的{上移,则可以去掉。

二维数组的遍历

for i := 0; i < 2; i++ {
	for j := 0 ; j < 3; j++ {
		fmt.Println(a[i][j])
	}
}

7.Go函数

函数定义

func function_name( [parameter list] ) [return_type] {
	...
}

定义一个返回两数最大值的函数:

func Max(a,b int) int {
	if(a>b) {
		return a
	} else {
		return b
	}
}

函数参数传递方式

分为两种传递方式:

值传递: 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递: 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

不定函数参数传递方式:
Golang 可变参数本质上就是 slice。只能有一个,且必须是最后一个。
在参数赋值时可以不用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可。

  func myfunc(args ...int) {    //0个或多个参数
  }

  func add(a int, args…int) int {    //1个或多个参数
  }

  func add(a int, b int, args…int) int {    //2个或多个参数
  }

使用时,若使用slice传递参数,需要展开写法 即加上...

func main() {
    s := []int{1, 2, 3}
    res := test("sum: %d", s...)    // slice... 展开slice
    println(res)
}

函数闭包(匿名函数)

Go语言支持匿名函数,即内联的语句或表达式,匿名函数的优点是可以直接使用函数内部的局部变量。

func(x int) {
	fmt.Printf("func 2, x is %d\n", x)
}(2)
//最后一个()直接跟参数列表是指函数直接调用

a := func(x int) int {
	fmt.Printf("func 3, x is %d\n", x)
	return 5
}

8.Go指针

指针定义

使用方式同 C++ 一样

声明一个指针
var ptr *int

指向某一元素
var a int = 1
ptr = &a

获取指针的值直接解引用即可,否则获取的就是指针指向的地址。

在Go语言中空指针使用nil表示,意义同其他语言的NULL、null,都代指零值或空值。

指针数组

本质是数组,数组中的每个元素皆为指针,指向其他的地址。

声明一个指针数组
var ptr [10] *int

多级指针

Go语言同C++一样,支持多级指针,即指向指针的指针。

var a int = 1
var ptr1, ptr2 *int
ptr1 = &a 
ptr2 = ptr1

9.Go结构体

定义结构体

使用type和struct定义结构体

type struct_name struct{
	number1 type1
	number2 type2
	...
}

//定义结构体
type book struct{
	int a
	string b
}
var p = book{1,"123"}
var g = book{a:1,b:"123"}

访问结构体成员

var p book
p.a = 1 
p.b = "123"

结构体指针

var p *book
p = &g //g是已初始化的结构体

调用时,直接使用.访问结构体成员

构造函数

Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个person的构造函数。 因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。

func newPerson(name string, city string, age int8) *person {
    return &person{
        name: name,
        city: city,
        age:  age,
    }
}

调用构造函数

p9 := newPerson("pprof.cn", "测试", 90)
fmt.Printf("%#v\n", p9)

10.Go切片(Slice)

Go语言中切片是对数组的抽象,切片相对与数组而言,长度不是固定的,可在末尾追加元素,类似于C++中vector容器。

定义切片

var Slice_name []type
例如: var s [] int //不需要定义长度

使用make创建切片:
var Slice_name = make([]type, len)
可简写为: Slice_name := make([]type, len)


其中make 可以有第三个参数capacity,表示最大容量 可被省略

初始化切片

例如:	s := []int{1, 2, 3} 其中len = capacity = 3
s := arr[:] //初始化切片s, 是数组 arr 的引用
s := arr[startIndex:endIndex] //将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片
s := arr[startIndex:] //默认 endIndex 时将表示一直到arr的最后一个元素
s := arr[:endIndex] //默认 startIndex 时将表示从 arr 的第一个元素开始
s1 := s[startIndex:endIndex] //通过切片s初始化切片s1

使用len()函数可获取切片的长度,使用cap()函数获取切片的容量。

注意:当切片被定义但未被初始化时,默认为nil,长度为0。

append()、copy()函数

//append()函数
var number []int
fmt.Println(number,len(number),cap(number))// [] 0 0
number = append(number,1)
fmt.Println(number,len(number),cap(number))// [1] 1 1
number = append(number,2,3,4)
fmt.Println(number,len(number),cap(number))// [1,2,3,4] 4 4

//copy()函数
number1 := make(int[],len(number),(cap(number)*2))
copy(number1,number)

Go范围(Range)

Go语言中使用Range关键字对for循环中数组array、切片slice、通道channel或集合map。

在数组和切片中返回两个值,即元素的索引的索引对应的值(key-val)。

如果不需要对对一个key进行访问,可使用 _ 代替。

var arr = []int{1,2,3,4}//定义一个切片
sum := 0
for i, val := range arr {//遍历切片
	sum += val
	if(i == 1) {
		fmt.Println(i)
	}
}
fmt.Println(sum)
mp := map[int]int {1 : 2, 2 : 3, 3 : 4}//定义集合map
for _, val := range mp {
	fmt.Println(val)
}
s := "123"
for _, val := range s {//遍历字符串
	fmt.Println(val)
}

Go集合(Map)

Go语言中map是无序的键值对,使用hash表实现。

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

//如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

//实例:
var mp map[string]int
mp = make(map[string]int)
mp["1"] = 2

delete()函数

使用delete删除map中的键值对,删除时只需要表名删除的key即可

接上例:
delete(mp,"1")//删除mp[1]的内容

Go并发

goroutine

Go语言通过go关键字来开启goroutine即可。

goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。

goroutine语法格式:
go 函数名(参数列表)
例如: go f(x,y,z)

Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。

channel

管道,用于传递数据的一个数据结构。

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- v //把v发送到通信ch
v := <- ch //从ch接收数据 并赋值给v

声明channel
ch := make(chan int)

注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。

package main

import "fmt"

func sum(s []int, c chan int) {
	sum := 0
	for _, v := range s {
		sum += v
	}
	c <- sum // 把 sum 发送到通道 c
}

func main() {
	s := []int{7, 2, 8, -9, 4, 0}

	c := make(chan int)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x, y := <-c, <-c // 从通道 c 中接收

	fmt.Println(x, y, x+y)
}
//-5 17 12

协程具有无序性。

channel缓冲区

通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:
ch := make(chan int, 100)

Go遍历通道与关闭通道

Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片。

package main

import (
        "fmt"
)

func fibonacci(n int, c chan int) {
        x, y := 0, 1
        for i := 0; i < n; i++ {
                c <- x
                x, y = y, x+y
        }
        close(c)
}

func main() {
        c := make(chan int, 10)
        go fibonacci(cap(c), c)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
        // 会结束,从而在接收第 11 个数据的时候就阻塞了。
        for i := range c {
                fmt.Println(i)
        }
}
//0 1 1 2 3 5 8 13 21 34

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Go语言学习笔记.pdf》是一本关于Go语言学习学习笔记,内容丰富且简洁明了。本书从基础知识开始,逐步介绍了Go语言的语法、特性和常用库函数等。在学习笔记,作者通过实际的示例和练习帮助读者理解Go语言的概念和用法。 第一章介绍了Go语言的起源和发展,为读者提供了对Go语言背景的整体了解。第二章讲解了Go语言的基本语法,例如变量声明、循环和条件语句等。通过大量的代码示例,读者能够更好地理解Go语言的语法和结构。 接下来的章节重点介绍了Go语言的并发编程和高级特性。第三章详细介绍了Go语言的goroutine和channel,这是Go语言并发编程的核心机制。作者通过生动的示例代码和实际应用案例,向读者展示了如何使用goroutine和channel实现并发编程。 第四章和第五章分别介绍了Go语言的面向对象编程和函数式编程。通过深入讲解Go语言的结构体、接口和函数,读者能够更好地应用这些特性进行代码设计和开发。 最后几章则介绍了Go语言常用的库函数和工具。例如,第六章介绍了Go语言用于网络编程的net包和http包。读者可以学习到如何使用这些库函数构建基于网络的应用程序。 总的来说,《Go语言学习笔记.pdf》是一本非常实用的Go语言学习资料。通过阅读这本书,读者能够系统地学习和理解Go语言的基本概念和高级特性,为之后的Go语言开发打下坚实的基础。无论是初学者还是有一定编程经验的开发者,都能从获得丰富的知识和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值