Go语言学习笔记这一堆主要是《Go语言编程》(人民邮电出版社)的读书笔记。中间会穿插一些零碎的点,比如源码学习之类的。大概就是这样吧。

1. 顺序编程

1.1 变量

变量的声明:

var 变量名 类型

var v1 int

也可以把若干变量的声明用大括号括起来

var {
v1 int
v2 string
}

变量初始化:

变量的初始化可以用如下的方法:

var v1 int = 10
var v2 = 10
v3 := 10

这三种方法的效果大体上是一样的。需要注意的有:第三种方法不能用于声明全局变量;以及:=赋值符号不能用于已声名过的变量名。

变量的赋值:

赋值这里唯一特别的是,Go语言支持多重赋值,比如交换i和j的值:

i, j = j, i

匿名变量:

Go语言有一个特性,就是在引入的包和变量在没有使用的时候,会在编译阶段报错。所以对于不需要的变量,可以使用匿名变量进行处理。

两个例子,第一个是多重返回函数的返回值的处理:

func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
} _, _, nickName := GetName()

如果只需要函数的部分返回值的时候,就可以利用匿名变量。

第二个是for循环:

var a int[] = {5, 4, 3, 2, 1}
for _, value := range(a) {
balabala
}

当我们不需要range返回的部分结果的时候,就可以利用匿名变量。

1.2 常量

字面常量:大概只有一点要说,就是不需要额外做特别的声明。比如对于long类型的12,不存在12l这种写法。

常量定义:通过const关键字进行定义。

const Pi float64 = 3.1415926

需要注意的大概有:声明的时候可以不限定类型;常量定义的右值也可以是编译期运算的常量表达式。

const Zero = 0.0
const mask = 1 << 3
const Home = os.GetEnv("HOME")

这里第三句会导致错误。因为右值只有在运行期才能知道结果。

预定义常量:true,false,iota。

这里true和false没有什么说的。

iota可以被认为是一个可被编译器修改的常量,该常量在每一个const关键字出现的时候被重置为0。在下一个const出现之前,每出现一次iota,其所代表的数字自动加1。

Golang不支持enum关键字的枚举类型,通常把const和iota结合起来表示枚举,例如:

const {
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays
}

这样就将星期与整数对应了起来。

注意,numberOfDays并没有被导出。

1.3 类型

Golang支持以下类型:

基本类型:布尔型,整型,浮点型,复数型,字符串,字符型,错误型。

复合类型:指针,数组,切片,字典,通道,结构体,接口。

基本类型中,需要注意的问题如下;

int和int32在Golang中被认为是不同的两个类型。所以二者不能互相赋值(编译期不会自动做类型转换),需要进行强制的类型转换。

自动推导的浮点数类型是float64。

复数类型是其他大部分语言不支持的。例子如下:

var value1 complex64

value1 = 3.2 + 12i
value2 := 3.2 + 12i
value3 := complex(3.2, 12) x := real(value1)
y := imag(value1)

字符串可以用下表的方式获取其内容,但是字符串在初始化之后,其内容就不能进行修改了。

字符串的遍历,这还跟len()函数作用在字符串上的返回值有关,例子如下:

str := "Hello, 世界"
n := len(str) //n = 13
for i:=0, i<n, i++ {
fmt.Println(i, str[i])
} for i, ch := range str {
fmt.Println(i, ch)
} //该段代码输出了9行结果

另外需要注意的,range有两个返回值,第一个是下标,第二个是下标对应的值。

数组在声明了以后,就不能再修改其长度。

数组切片的实质可以理解成3部分:一个指向原数组的指针;数组切片中的元素个数;数组切片已分配的存储空间。

数组切片的声明方式如下:

//基于数组创建数组切片
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var mySlice []int
mySlice = myArray[:] //基于所有数组元素创建切片
mySlice = myArray[:5] //基于数组的前5个(0~4)元素创建切片
mySlice = myArray[5:] //基于数组第5个开始(5~end)的元素创建切片 //直接创建数组切片
mySlice1 := make([]int, 5) //创建一个初始长度为5的数组切片,元素初始值是0
mySlice2 := make([]int, 5, 10) //除以上之外,预留了10个元素的存储空间
mySlice3 := []int{1, 2, 3, 4, 5} //直接创建并初始化一个包含5个元素的数组切片

append函数可以增加切片的元素。注意append函数并不是原地的。其应用例子如下:

mySlice := make([]int, 2, 10)

mySlice = append(mySlice, 1)
mySlice = append(mySlice, 2, 3) mySlice2 := []int{4, 5}
mySlice = append(mySlice, mySlice2...)

注意最后的...,它将mySlice2的元素打散做为append的参数。

也可以通过数组切片来创建切片。例如:

oldSlice := make([]int, 5, 10)
newSlice1 := oldSlice[:3] //用oldSlice的前三个元素创建新的切片
newSlice2 := oldSlice[:7] //也可以超出原切片的数量,但是不能超过cap,超出的部分填0

copy函数可以将一个数组切片的内容复制到另一个数组切片。例如:

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{6, 7, 8} copy(slice2, slice1) //复制slice1的前三个元素到slice2
copy(slice1, slice2) //复制slice2到slice1的前三个位置

map的元素查找可以用以下方法:

myMap := make(map[string]int, 100)    //声明一个map,cap为100

value, ok := myMap["1234"]
if ok { //找到了
//对value的处理
}

1.4 流程控制

条件语句if的例子如下:

if a < 5 {
return 0
} else {
return 1
}

需要注意的有:条件语句不需要括号;花括号必须存在;以及最重要的,不允许将最终的return包含在if...else...结构中。

选择语句switch的例子如下:

switch i {
case 0:
fmt.Println(0)
case 1:
fmt.Println(1)
fallthrough
case 3:
fmt.Println(3)
default:
fmt.Println("Default")
}

需要注意的有:除非明确的标明fallthrough,否则认为分支默认break;另外,switch后面的条件表达式也可以不设定,这时可以将switch看作是多个if...else...。

循环语句if的例子如下:

for i := 0; i < 10; i++ {
fmt.Println(i)
} j := 0
for j<10 {
fmt.Print(j)
j++
} k := 0
for {
fmt.Print(k)
k++
if k>10 {
break
}
}

总之,Golang是把for和while结合到了一起。同时,也有break和continue。break也可以选择中断哪个循环。

goto就是跳转到label。这个很少用,先写在这里。

1.5 函数

函数的定义和调用:

package mymath
import "errors" func Add(a int, b int) (ret int, err error) {
if a<0 || b<0 {
err = errors.New("Should be non-negative numbers!")
return
}
return a + b, nil
} c := mymath.Add(1, 2)

需要注意的有:函数、类型和变量的可见性是由其首字母的大小写来确定的,大写开头的是public,小写开头的是private;函数的返回值的变量名可以先声明出来,在函数体内对变量进行处理后直接return即可;函数可以同时返回多个值。

同时,Golang的函数也支持不定参数,例如:

func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
} myfunc(2, 3, 4)
myfunc(1, 3, 7, 13) func myfunc2(args ...int) {
myfunc(args...)
myfunc(args[1:]...)
}

通过例子可以看到不定参数的函数的遍历方法和调用方法。以及作为变参函数嵌套的传参方法。我觉得最关键的是记住,...在跟类型一起出现的时候,表明的是变参类型;...在跟变量名一起出现的时候,表明是将该变量内容打散。这种记法与*和&的区别方法一致。

如果希望传递任意类型的不定参数,可以利用interface{}。这里先举一个例子,后面会再具体描述interface{}。

func MyPrintf(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
fmt.Println(arg, "int")
case string:
fmt.Println(arg, "string")
default:
fmt.Println(arg, "unknown")
}
}
}

匿名函数简单的说就是没有函数名的函数。匿名函数可以赋值给一个变量名,也可以直接执行。例如:

f := func(x, y int) int {
return x + y
} func (ch chan int) {
ch <- ACK
} (reply_chan)

立即执行的匿名函数,需要把传入的参数放到函数后面的括号中。

这里还有一个闭包的概念,目前还没太懂,待补充。

错误处理,Golang提供了error,defer,panic和recover工具。

error是一个接口,其定义如下:

type error interface {
Error() string
}

对于需要返回错误的函数,多数情况下定义成下面的形式,并按以下方式调用:

func Foo(param int) (n int, err error) {
// ...
} n, err := Foo(0)
if err != nil {
// 错误处理
} else {
// 使用返回值n
}

那么,对于自定义的error类型(即实现了error接口的类型),通常定义的形式如下:

type PathError struct {
Op string
Path string
Err error
} func (e *PathError) Error() string {
return e.Op + " " + e.Path + ": " + e.Err.Error()
} func Stat (name string) (fi FileInfo, err error) {
var stat syscall.Stat_t err =syscall.Stat(name, &stat)
if err != nil {
return nil, &PathError{"stat", name, err}
} return fileInfoFromStat(&stat, name), nil
}

defer关键字主要是用来处理代码中需要在最后完成的任务,比如关闭管道,关闭文件等。例子如下:

func CopyFile(dst, src string) (w int64, err error) {
srcFile, err := os.Open(src)
if err != nil {
return
}
defer srcFile.Close()
return io.Copy(dstFile, srcFile)
}

另外,如果一个函数中有多个defer关键字,那么它们是以后进先出的方式(即自下而上的)执行。

panic和recover两个函数是Golang中用来处理异常的函数。其流程大致为:当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。recover()函数用于终止错误流程。一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程,会导致该goroutine所属的进程打印异常信息后直接退出。

常见的recover()调用方法如下:

defer func() {
if r := recover(); r != nil {
log.Printf("Runtime error caught: %v", r)
}
}()

这样写,无论函数中是否出发了错误处理流程,该匿名函数都将在函数退出时得到执行。

第一节大概是这样~如果有任何问题还会及时更新~~~

Go语言学习笔记(1)——顺序编程的更多相关文章

  1. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  2. 孙鑫VC学习笔记:多线程编程

    孙鑫VC学习笔记:多线程编程 SkySeraph Dec 11st 2010  HQU Email:zgzhaobo@gmail.com    QQ:452728574 Latest Modified ...

  3. 2017-04-21周C语言学习笔记

    C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...

  4. 2017-05-4-C语言学习笔记

    C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...

  5. java学习笔记15--多线程编程基础2

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...

  6. 《C# 语言学习笔记》——目录

    C# 简介 变量和表达式 流程控制 3.1 布尔逻辑 3.2 goto语句 3.3 分支 3.4 循环 变量的更多内容 4.1 类型转换 4.2 复杂的变量类型 4.3 字符串的处理 函数 5.1 定 ...

  7. 《C# 语言学习笔记》——C# 简介

    1 什么是.NET Framework .NET Framework 是Microsoft为开发应用程序而创建的一个富有革命性的新平台. 1.1 .NET Framework 的内容 .NET Fra ...

  8. Hadoop学习笔记(7) ——高级编程

    Hadoop学习笔记(7) ——高级编程 从前面的学习中,我们了解到了MapReduce整个过程需要经过以下几个步骤: 1.输入(input):将输入数据分成一个个split,并将split进一步拆成 ...

  9. WCF学习笔记之事务编程

    WCF学习笔记之事务编程 一:WCF事务设置 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元: WCF通过System.ServiceModel.TransactionFlowA ...

随机推荐

  1. Spring IOC 笔记

    什么是IOC与DI IOC(inversion of control) 它描述的其实是一种面向对象编程中的设计原则,用来降低代码之间的耦合度, 而DI(dependency Injection)依赖注 ...

  2. Linux 时间同步 05 chrony时间同步

    Linux 时间同步 05 chrony时间同步 目录 Linux 时间同步 05 chrony时间同步 chrony 的优势: chrony包介绍 安装chrony 配置与外部时间服务器进行时间同步 ...

  3. 转 linux终端 字符界面 显示乱码 .

    方法一:配置SSH工具 SecureCRT中文版配置 [全局选项]→[默认会话]→[编辑默认设置]→[终端]→[外观]→[字体]→[新宋体 10pt CHINESE_GB2312]→[字符编码 UTF ...

  4. ethernet

    OSI参考模型 简化相关网络操作:提供不同厂商之间的互联 应用层 为应用程序提供服务 HTTP Telnet 表示层 数据格式化,加密.解密 ASCII EBCDIC JPEG 会话层 建立.维护.管 ...

  5. openstack octavia的实现与分析(二)原理,架构与基本流程

    [了解] 其实说白了,Octavia就是将用户的API请求经过逻辑处理,转换成Haproxy或者Nginx的配置参数,下发到amphora虚机中. Octavia的内部实现中,逻辑流程的处理主要使用T ...

  6. 利用css和jquery制成弹幕

    1.首先上图看下效果 2.废话不多说,直接上代码 1>html代码 <div class="barrage"> <div class="scree ...

  7. 【Git】4、创建代码仓库,HTTP、SSH拉取远端代码

    拉取远端代码:使用Git命令下载远程仓库到本地 文章目录 拉取远端代码:使用Git命令下载远程仓库到本地 1.创建远程代码仓库 2.创建仓库 3.进入仓库 4.HTTP(S)获取远程仓库 首次拉取 更 ...

  8. innodb是怎么刷新日志缓冲的

    当innodb把日志缓冲刷新到磁盘日志文件的时候,先会用一个mutex锁住缓冲区,刷新到所需要的位置,然后移动剩下的条目到缓冲区的前面,当mutex释放时,可能有超过一个事务已经准备好刷新其日志记录, ...

  9. VS2019项目docker启动且访问SQLSERVER数据库配置

    VS2019编译.调试的Blazor纯前台项目,使用控制台启动,去连接纯后台的API项目,使用docker启动,并且通过EFCore访问SQLSERVER数据库,有几个地方需要修改配置: 一.前台连后 ...

  10. Test typora

    目录 0. test 0.5 easy test 1. problem 1 2. problem 2 3. problem 3 import numpy as np import matplotlib ...