go语言学习笔记

最近一直在学习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
&#xE4;
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">!

&#x4F60;
&#x597D;
,
&#x4E16;
&#x754C;
<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的概念, 但又不完全一样. 我们这里详细提几点.

  1. 切片的创建 切片有两种创建方式, 一种是基于数组创建, 另一种是用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... //...&#x8868;&#x793A;&#x662F;&#x62C6;&#x6210;&#x4E00;&#x4E2A;&#x4E2A;&#x5143;&#x7D20;&#x4F20;&#x9012; 匿名函数的概念也很简单, 只要看代码就会明白.

<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/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • go程序添加远程调用tcpdump功能

    最近开发的telemetry采集系统上线了。听起来高大上,简单来说就是一个grpc/udp服务端,用户的机器(路由器、交换机)将它们的各种统计数据上报采集、整理后交后端的各类AI分…

    Go语言 2023年5月25日
    058
  • 基于LSM的Key-Value数据库实现稀疏索引篇

    上篇文章简单的填了一个坑基于LSM数据库的实现了WAL,在该版本中如数据写入到内存表的同时将未持久化的数据写入到WAL文件,在未将数据持久化时程序崩溃,可通过WAL文件将数据还原恢…

    Go语言 2023年5月25日
    071
  • Go sort包

    sort包简介 官方文档Golang的sort包用来排序,二分查找等操作。本文主要介绍sort包里常用的函数,通过实例代码来快速学会使用sort包 sort包内置函数 sort.I…

    Go语言 2023年5月25日
    093
  • Go语言之高级篇beego框架之layui框架应用

    1、layui前端框架 参考地址:https://www.layui.com Original: https://www.cnblogs.com/nulige/p/10396542…

    Go语言 2023年5月29日
    046
  • 为 Memcached 构建基于 Go 的 Operator 示例

    Operator SDK 中的 Go 编程语言支持可以利用 Operator SDK 中的 Go 编程语言支持,为 Memcached 构建基于 Go 的 Operator 示例、…

    Go语言 2023年5月25日
    051
  • Go语言之网络编程

    一、网络编程基础 网络基础之TCP/IP协议族 网络编程之socket 二、TCP Socket编程 (一)流程 首先应该了解服务端和客户端的处理流程: 1、服务端处理流程 监听端…

    Go语言 2023年5月29日
    056
  • Go语言之高级篇Beego框架之爬虫项目实战

    一、爬虫项目 1、爬虫基础 a、网页上面会有相同的数据 b、去重处理 布隆过滤器哈希存储 c、标签匹配: 正则表达式beautiful soup或lxml这种标签提取库 d、动态内…

    Go语言 2023年5月29日
    050
  • Go语言结构应用实例

    编写程序过程中,经常会用到结构。本程序给出了使用结构的简单实例。 Go语言程序: // struct project main.go package main import ( &…

    Go语言 2023年5月29日
    046
  • 使用Go搭建并行排序处理管道笔记

    go;collapse:true;;gutter:true; package main</p> <p>import ( "bufio" …

    Go语言 2023年5月25日
    049
  • 字符集与编码

    一个比特(bit)可以是0,或者是1,8个比特(bit),组成一个字节(byte)。全为0时代表数字0,全为1时代表数字255。 一个字节可以表示256个数字,两个字节可以表示65…

    Go语言 2023年5月25日
    041
  • Go语言之循环与条件判断

    Go 语言中没有 while 循环,只有一个 for 循环 for 变量初始化;条件;变量自增/自减 { 循环体内容 } 1、基本使用 for i := 0; i < 10;…

    Go语言 2023年5月25日
    052
  • Go基础知识梳理(三)

    Go基础知识梳理(三) 结构 type Person struct { name string sex int } func main() { //&#x63A8;&amp…

    Go语言 2023年5月25日
    059
  • 解决go-micro与其它gRPC框架之间的通信问题

    在之前的文章中分别介绍了使用gRPC官方插件和go-micro插件开发gRPC应用程序的方式,都能正常走通。不过当两者混合使用的时候,互相访问就成了问题。比如使用go-micro插…

    Go语言 2023年5月25日
    067
  • 【golang】分布式缓存 – lru算法实现

    最近复习操作系统,看到了lru算法,就去网上搜索下,因此发现了GeeCache,顺手写了一遍。研究下lru算法的实现。 正文: lru使用map+链表实现。map里面存储了key以…

    Go语言 2023年5月25日
    033
  • Go语言之如何给*int32类型赋值

    直接上代码: package main import “fmt” func main () { var num *int32 var i int32 = 5…

    Go语言 2023年5月29日
    044
  • Excelize 发布 2.6.1 版本,支持工作簿加密

    Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Mic…

    Go语言 2023年5月25日
    057
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球