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. JAVA NIO Selector Channel

    These four events are represented by the four SelectionKey constants: SelectionKey.OP_CONNECT Select ...

  2. javascript 匿名函数的理解(转)

    原网址 http://www.jb51.net/article/21948.htm javascript 匿名函数的理解(透彻版) 代码如下: (function(){ //这里忽略jQuery所有实 ...

  3. java集合并发操作异常解决方法:CopyOnWriteArrayList

    一.我们知道ArrayList是线程不安全的,请编写一个不安全的案例并给出解决方案 HashSet与ArrayList一致 HashMap HashSet底层是一个HashMap,存储的值放在Hash ...

  4. linux操作系统可以ping通ssh连接长时间无响应

    一.问题描述 某集群数据节点服务器频繁无法连接,服务器间出现可ping通但ssh无法连接的情况,使用带外地址登录后远程控制也无法显示正常界面,重启后会短暂恢复. 二.排查问题 重启服务器后检查服务器S ...

  5. 一文详解 ARP 协议

    我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 公众号连载计算机网络文章如下 ARP,这个隐匿在计网 ...

  6. DM TDD使用小结

    1.搭建流程 1.1 ss初始化及启动 --->1节点: cd /dm/bin ./dmdssinit path=/dm/data inst=ss1 port=35300 REGION_SIZE ...

  7. JavaCV更新到1.5.x版本后的依赖问题说明以及如何精简依赖包大小

    javaCV全系列文章汇总整理 javacv教程文档手册开发指南汇总篇 前言 JavaCV更新到1.5.x版本,依赖包也迎来了很大变化,体积也变大了不少.很多小伙伴们反馈,之前很多1.3.x和1.4. ...

  8. 【JDBC核心】数据库连接池

    数据库连接池 传统模式 使用数据库的传统模式: 在主程序(servlet.beans等)中建立数据库连接: 进行 SQL 操作: 断开数据库连接. 这种模式存在的问题: JDBC 连接数据库的方式(四 ...

  9. SQLI-LABS复现通关

    sql-lab 复现通关(深入学习) less-1 基于错误的单引号字符串 - 正常访问 127.0.0.1/?id=1 - 添加 ' 返回报错信息:You have an error in your ...

  10. docker 报错: Cannot connect to the Docker daemon at unix:///var/run/docker.sock.

    最近在 Windows 子系统 WSL 上面安装了一个 ubuntu18.04, 安装完docker 跑 hello-world 的时候报错了 docker: Cannot connect to th ...