最近一直在学习go语言,因此打算学习的时候能够记录
一下笔记。我这个人之前是从来没有记录笔记的习惯,
一直以来都是靠强大的记忆力去把一些要点记住。
读书的时候因为一直都是有一个很安静和很专心的环境,
因此很多事情都能记得很清楚,思考的很透彻。但是随着
年纪不断增加,也算是经历了很多的事情,加上工作有时会让人
特别烦闷,很难把心好好静下来去学习,去思考大自然的终极
奥秘,因此需要记录一些东西,这些东西一方面可以作为一种自我激励
的机制,另一方面,也算是自己成长的轨迹吧。
一. 顺序编程
go语言变量定义的关键字是 var。类型放在变量名后:
每一行不需要以分号作为结尾。 var
关键字还有一种是把多个变量的申明放在一起,
有人说,变量初始化有什么好提的,那么简单。是的,但是这里面确实还是有一些值得注意的点。
第三种初始化方式无疑是最简单的。
但是要注意的是,这里面第三种方式是和特别的,比如
等价于
这时候就会报一个重复定义的错误。
变量赋值和我们通常的语言基本是一致的,但是多了多重赋值功能。
i,j=j,i
这就直接实现了两个变量的交换。
go语言的函数是多返回值的,因此可能有些值并没有被用到,这时我们就需要一个占位符去忽略这些返回值。
通过 const关键字,可以用来定义常量。
常量的定义也可以跟一个表达式, 但是这个表达式应该是编译的时候就可以求值的.
这里要讲一个很有意思的东西, 叫做 iota.
这个东西每一个const出现的位置被置为0,没出现一个iota出现,都自增1,到写一个const出现的时候,又置为0.
如果两个const赋值表达式是一样的,可以省略后面的赋值表达式.
大写字母开头的包外可见, 小写字母开头的包外不可见.
-
整型 int8, uint8, int16, uint16,int32, uint32, int64, uint64, int, uint, uintptr 不同类型不能相互比较.
-
浮点类型 float32, float64 涉及的一些运算比较简单, 我们不做细讲.
-
字符串类型 下面我们展示一个完整的go语言程序, 也是以hello
world为主题, 毕竟hello world是一个万斤油的主题.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
这基本上是一个最简单的程序了,但是对于我们的学习非常有用,用这个模板可以写出非常好的东西出来. 字符串串本身非常简单,主要就是一些字符串操作, 比如取特定位置的字符等.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果为:
hello,world!
h
12
ä
13
这正好说明[]和len都不能处理中文. 字符串连接也是用+. 字符串的遍历:
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
h
e
l
l
o
,
w
o
r
l
d
<span class="hljs-addition">!</span>
对于中文, 结果是乱码, 因为是一个字节一个字节输出的, 但是默认是UTF8编码, 一个中文对应3个字节.
这里我们要提到一个 range的关键字, 它可以把字符串按键值对的方式返回.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果为:
h
e
l
l
o
,
w
o
r
l
d
<span class="hljs-addition">!
你
好
,
世
界
<span class="hljs-addition">!</span></span>
事实上, 字符类型有两种, 一种就是byte(uint8), 另一种是rune. 第一种遍历字符串ch是byte, 而第二种是rune.
- 数组 数组这种类型是非常常见的
[<span class="dv"><span class="hljs-number">32]<span class="dt"><span class="hljs-keyword">byte
[<span class="dv"><span class="hljs-number">2*N] <span class="kw"><span class="hljs-keyword">struct { x, y <span class="dt"><span class="hljs-keyword">int32 }
[<span class="dv"><span class="hljs-number">1000]*<span class="dt"><span class="hljs-keyword">float64
[<span class="dv"><span class="hljs-number">3][<span class="dv"><span class="hljs-number">5]<span class="dt"><span class="hljs-keyword">int
[<span class="dv"><span class="hljs-number">2][<span class="dv"><span class="hljs-number">2][<span class="dv"><span class="hljs-number">2]<span class="dt"><span class="hljs-keyword">float64</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
数组的遍历和字符串一样,这里不再重复. 数组是值类型,在赋值时会拷贝一份.
* 数组切片 数组切片的概念比较复杂, 它有点类似于c++中vector的概念, 但又不完全一样. 我们这里详细提几点.
- 切片的创建 切片有两种创建方式, 一种是基于数组创建, 另一种是用make创建.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
slice是引用类型.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
我们发现数组确实是按照值来传递. 那么如果是slice呢, 会发生什么?
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
1
2
3
4
5
6
7
8
9
10
10
2
3
4
5
6
7
8
9
10
确实是按照引用来传递的. append函数可以往切片尾部增加元素. mySlice = append(mySlice, 1, 2, 3)
mySlice = append(mySlice, mySlice2...)
…表示把一个slice拆成元素来处理.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
[<span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0]
<span class="hljs-number">0xc820012190
[<span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">1 <span class="hljs-number">2 <span class="hljs-number">3]
<span class="hljs-number">0xc820012190
[<span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">0 <span class="hljs-number">1 <span class="hljs-number">2 <span class="hljs-number">3 <span class="hljs-number">1 <span class="hljs-number">2 <span class="hljs-number">3]
<span class="hljs-number">0xc82005e000</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
在这里我们看到,slice的地址是所随着内内存的改变而变化的,因此是需要仔细思考的.我个人不觉得
go语言这种特性有什么好的,反正也是奇葩极了. 不过slice还提供copy, 也算是一些弥补吧.
- map go语言中,map使用非常简单.基本上看代码就会了.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果为:
<span class="hljs-built_in">map[<span class="hljs-number">12345:{hanmeimei <span class="hljs-number">20} <span class="hljs-number">123456:{dagong <span class="hljs-number">30} <span class="hljs-number">1234:{lilei <span class="hljs-number">100}]
<span class="hljs-built_in">map[<span class="hljs-number">1234:{lilei <span class="hljs-number">100} <span class="hljs-number">12345:{hanmeimei <span class="hljs-number">20}]
{lilei <span class="hljs-number">100}
<span class="hljs-number">12345:hanmeimei
<span class="hljs-number">1234:lilei</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
map很简单吧. 数据结构我们讲完了, 接下来可以看看代码的程序控制了.
程序控制本人只提一些关键性的东西,不会啰嗦太多.
- switch语句 switch语句不需要在每个case地下写break,默认就是执行break.如果要执行多个case, 在case最后加入fallthrough.
条件表达式不限制为常量或者整数.单个case自然可以有多个结果可以选.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
- 循环 go语言的循环比较特别, 它用一个for就把for和while的活都干了.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
break还支持break到指定的label处.
<span class="kw"><span class="hljs-keyword">for j := <span class="dv"><span class="hljs-number">0; j < <span class="dv"><span class="hljs-number">5; j++ {
<span class="kw"><span class="hljs-keyword">for i := <span class="dv"><span class="hljs-number">0; i < <span class="dv"><span class="hljs-number">10; i++ {
<span class="kw"><span class="hljs-keyword">if i > <span class="dv"><span class="hljs-number">5 {
<span class="kw"><span class="hljs-keyword">break JLoop
}
fmt.Println(i)
}
}
JLoop:
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
- 函数 函数是一个非常重要的概念, 也很简单. go的函数以func关键字定义, 支持不定参数和多返回值. 函数名首字符的大小写是很有讲究的: 小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。这个规则也适用于类型和变量的可见性。
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
很简单吧. 注意, 如果是函数里面调了其他函数, 那么这个sample怎么传给其他喊函数呢? sample... //...表示是拆成一个个元素传递
匿名函数的概念也很简单, 只要看代码就会明白.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
下面是关于闭包的概念. 这个概念在许式伟的书中被诠释的非常好: 闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,
而是在定义代码块的环境中定义。
要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定定的计算环境(作用域)。
闭包的实现确保只要闭包还被使用,那么被闭包引用的变量会一直存在.* 我们来看来两个闭包的例子.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
11
0xc82000a288
12
0xc82000a2c0
我们从这个结果中发现, i的地址是会变的, 因为是作为一个局部变量传进去的.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import <span class="st"><span class="hljs-string">"fmt" </span></span></span></span></span></span>
输出结果:
0xc82000a288
11
0xc82000a288
21
因为x只传入了一次, 因此没有改变.
<span class="kw"><span class="hljs-keyword">package main
<span class="kw"><span class="hljs-keyword">import (
<span class="st"><span class="hljs-string">"fmt"
)
<span class="kw"><span class="hljs-keyword">func main() {
<span class="kw"><span class="hljs-keyword">var j <span class="dt"><span class="hljs-keyword">int = <span class="dv"><span class="hljs-number">5
a := <span class="kw"><span class="hljs-keyword">func() (<span class="kw"><span class="hljs-keyword">func()) {
<span class="kw"><span class="hljs-keyword">var i <span class="dt"><span class="hljs-keyword">int = <span class="dv"><span class="hljs-number">10
<span class="kw"><span class="hljs-keyword">return <span class="kw"><span class="hljs-keyword">func() {
fmt.Printf(<span class="st"><span class="hljs-string">"i, j: %d, %d<span class="ch"><span class="hljs-string">\n<span class="st"><span class="hljs-string">", i, j)
}
}()
a()
j *= <span class="dv"><span class="hljs-number">2
a()
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
此时输出:
<span class="hljs-built_in">i, <span class="hljs-built_in">j: <span class="hljs-number">10, <span class="hljs-number">5
<span class="hljs-built_in">i, <span class="hljs-built_in">j: <span class="hljs-number">10, <span class="hljs-number">10</span></span></span></span></span></span></span></span>
二. 面向对象编程
这里我们先提 值语义和 引用语义的概念.
如果b改变, a不发生改变, 就是值语义. 如果b改变, a也发生改变, 就是引用语义.
go语言大多数类型都是值语义, 比如:
基本类型: byte, int, float32, float64, string
复合类型: struct, array, pointer
也有引用语义的, 比如:
slice, map, channel, interface.
这是我们要牢记的.
我们的笔记整体式按照许式伟的书来安排, 但是由于许的书提纲性很强, 内容上不是很详细, 基本上会重新整理补充一些东西进去.
- *结构体
结构体是用struct来申明的, 不多废话, 直接上代码.
输出结果:
`
{dingding 10}
{dingding 10}
{dingding 10}
&{dingding 10}
&{ 0}
Original: https://www.cnblogs.com/zhuiluoyu/p/7289541.html
Author: 坠落鱼
Title: go语言学习笔记
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535772/
转载文章受原作者版权保护。转载请注明原作者出处!