前言

大半个月前我参与了字节后端面试,未通过第四面,面试总结写在了这篇文章:

https://juejin.cn/post/7132712873351970823

在此文的末尾,我写到为了全面回顾Go的知识点,我开始阅读《The Go Programing Language》,这是我接触Go以来第一次阅读英文书籍。并且希望将学习的笔记其整理成册。思前想后我决定开设一个Go语言学习的仓库,在其中更新我的笔记。并且放置一些Go的学习资料,以及之前面试使用的简历等杂项文档。

仓库地址:https://github.com/BaiZe1998/go-learning

而本文的内容就是部分的笔记,当前阅读至第三章,因此,笔记便同步更新至第三章,预计会用一个多月的时间完成这份笔记的更新。

区别于连篇累牍,我希望这份笔记是详略得当的,可能更适合一些对Go有着一些使用经验,但是由于是转语言或者速食主义者,对Go的许多知识点并未理解深刻(与我一般),笔记中虽然会带有一些个人的色彩,但是Go语言的重点我将悉数讲解。

再啰嗦一句:笔记中讲述一个知识点的时候有时并非完全讲透,或是浅尝辄止,或是抛出疑问却未曾解答。希望你可以接受这种风格,而有些知识点后续涉及到后续章节,当前未过分剖析,也会在后面进行更深入的讲解。

最后,如果遇到错误,或者你认为值得改进的地方,也很欢迎你评论或者联系我进行更正,又或者你也可以直接在仓库中提issue或者pr,或许这也是小小的一次“开源”。

一、综述

1.1 Hello Word

介绍包管理,编译依赖,运行代码的流程;无需分号结尾以及严格的自动格式化

1.2 命令行参数

参数初始化,获取命令行参数的方式,给出了一个低效的循环获取命令行参数的代码,在此基础上进行优化

关于字符串常量的累加(是否是不断创建新值,变量创建后如何存储,结合Java堆|栈)

1.3 查找重复行

strings.join底层发生了什么

map乱序的原因

os.stdin Scan的终止条件

输出错误内容到标准错误

何时可以跳过error检查

1.4 GIF 动画

可以生成gif格式的图片

1.5 获取一个URL

resp.Body.Close()可以avoid leaking resources,具体发生了什么

io.Copy(dst, src)与ioutil.ReadAll的工作模式区别

1.6 并发获取多个URL

当多个goroutine同时对一个channel进行输入输出的时候,会发生阻塞

1.7 实现一个 Web 服务器

fmt.Fprintf(dir, src)可以将内容输出到指定输出(web的response、标准错误),因为dir实现了接口(io.Writer)

启动服务程序的时候mac&linux为什么末尾要加&

服务端handler路由匹配到前缀则可以触发,并且开启不同goroutine处理request(那么上限是多少,高访问量会发生什么)

1.8 杂项

switch在满足case之后不会继续下沉,且default可以放置在任何位置

switch也可以以tarless的模式书写

goto语法不常用,但是go也提供了

func也可以作为一种类型

结构、指针、方法、接口、包、注释

二、程序结构

2.1 名字

包名通常小写字母命名

通常来说,对于作用域较短的变量名,Go推荐短命名,如i而不是index,而对于全局变量则倾向于更长,更凸显意义的命名

驼峰而非下划线命名

2.2 声明

注意全局变量的作用域最小也是整个包的所有文件,大写则可以跨包

2.3 变量

引用类型:slice、pointer、map、channel、function

可以同时初始化多种类型的变量,并且Go没有未初始化的变量

var x float64 = 100 // 此时不使用短变量命名

:= 是声明,而 = 是赋值

巧妙:如果:=左侧部分变量已经声明过(作用域相同),则只会对其进行赋值,而只声明+赋值未声明过的变量,且左侧必须至少有一个未声明才能用:=,且declarations outer block are ignored

x := 1
p := &x
*p = 2 // 则 x == 1

var x, y int
&x == &x, &x == &y, &x == nil // true false false

Go的flag包可以实现获取命令行参数的功能:-help的来源

p := new(int) // p是int类型的指针(或者某个类型的引用),此时*p == 0
*p = 2 // new 并不常用

垃圾回收:一个变量如果不可达(unreachable),则会被回收

关于变量的生命周期:全局变量在程序运行周期内一直存在,而局部变量则会在unreachable时会被回收,其生命周期从变量的声明开始,到unreachable时结束

栈内存:栈内存由编译器自动分配和释放,开发者无法控制。栈内存一般存储函数中的局部变量、参数等,函数创建的时候,这些内存会被自动创建;函数返回的时候,这些内存会被自动释放,栈可用于内存分配,栈的分配和回收速度非常快

堆内存:只要有对变量的引用,变量就会存在,而它存储的位置与语言的语义无关。如果可能,变量会被分配到其函数的栈,但如果编译器无法证明函数返回之后变量是否仍然被引用,就必须在堆上分配该变量,采用垃圾回收机制进行管理,从而避免指针悬空。此外,局部变量如果非常大,也会存在堆上。

在编译器中,如果变量具有地址,就作为堆分配的候选,但如果逃逸分析可以确定其生存周期不会超过函数返回,就会分配在栈上。

总之,分配在堆还是栈完全由编译器确定。而原本看起来应该分配在栈上的变量,如果其生命周期获得了延长,被分配在了堆上,就说它发生了逃逸。编译器会自动地去判断变量的生命周期是否获得了延长,整个判断的过程就叫逃逸分析。

/*
此时x虽然是局部变量,但是被分配在堆内存,在f()调用结束后依旧可以通过global获取x的内容,我们称x从f当中escape了

逃逸并非是一件不好的事情,但是需要注意,对于那些需要被回收的短生命周期的变量,不要在编程当中被长生命周期的变量(全局变量)引用,否则会很大程度上影响Go的垃圾回收能力,造成内存分配压力
*/
var global *int
func f() {
var x int
x = 1
global = &x
}
// 此时*y没有从g()当中escape,因此是分配在栈内存当中,调用结束变成unreachable,需要被回收
fun g() {
 y := new(int)
 *y = 1
}

2.4 赋值

x, y = y, x
a[i], a[j] = a[j], a[i]
// 计算斐波那契数列,=赋值右侧的表达式会按照旧值先计算后赋值给左侧变量
func fib(n int) int {
x, y := 0, 1
for i := 0; i < n; i++ {
x, y = y, x+y
}
}

2.5 类型声明

type IntA int
type IntB int

var (
 x IntA = 1 // 此时x和y是不同类型,因此无法比较与一起运算
 y IntB = 2
)

T(x)将x转成T类型,转换操作可以执行的前提是x和T在底层是相同的类型,或者二者是未命名的指针类型,底层指向相同的类型

这样的转换虽然转化了值的类型,但是并没有改变其代表的值

当然,数值类型的变量之间也允许这种转换(损失精度),或者将string转换成[]byte的切片等,当然这些转化方式将改变值的内容

2.6 包和文件

包中.go文件的初始化流程:

  1. 如果package p内部import了q,则会先初始化package q
  2. main package最后初始化,可以确保main func在执行时所有的package已经完成初始化

2.7 作用域

变量的scope(作用域)是处于compile-time(编译时)的特征

变量的lifetime(生命周期)是处于run-time(运行时)的特征

if x := f(); x == 0 {
 fmt.Println(x, y)
} else if y := g(x); x == y {
 fmt.Println(x, y)
} else {
 fmt.Println(x, y)
}
fmt.Println(x, y) // compile error: x and y are not visible here

变量作用域的测试如下:

func test() (int, error) {
return 1, nil
}

func main() {
x := 0

for i := 1; i <= 5; i++ {
x := i
fmt.Println(x, &x)
}
fmt.Println(x, &x) // 此时x依旧是0,说明for内部的x是重新声明的
 x, err := test() // 此时x和err通过:=声明+赋值,但是结合2.3节的内容,此时x已经声明,所以只对其进行赋值为1,但是地址不变
fmt.Println(x, &x, err) // 此处打印的x == 1时的地址与赋值前x == 0地址相同
}
// 结果
1 0x1400012a010
2 0x1400012a030
3 0x1400012a038
4 0x1400012a040
5 0x1400012a048
0 0x1400012a008
1 0x1400012a008 <nil>

三、基本数据类型

3.1 整数

负数的%运算

&^(位运算符:and not),x &^ y = z,y中1的位,则z中对应为0,否则z中对应为x中的位

00100010 &^ 00000110 = 00100000

无符号整数通常不会用于只为了存放非负整数变量,只有当涉及到位运算、特殊的算数运算、hash等需要利用无符号特性的场景下才会去选择使用

比如数组下标i用int存放,而不是uint,因为i--使得i == -1时作为判断遍历结束的标志,如果是uint,则0减1则等于2^64-1,而不是-1,无法结束遍历

注意:int的范围随着当前机器决定是32位还是64位

var x int32 = 1
var y int16 = 2
var z int = x + y // complie error
var z int = int(x) + int(y) // ok
// 大多数数值型的类型转换不会改变值的内容,只会改变其类型(编译器解释这个变量的方式),但是当整数和浮点数以及大范围类型与小范围类型转换时,可能会丢失精度,或者出现意外的结果

我开源了一个Go学习仓库|笔记预览的更多相关文章

  1. [个人开源]vue-code-view:一个在线编辑、实时预览的代码交互组件

    组件简介 vue-code-view是一个基于 vue 2.x.轻量级的代码交互组件,在网页中实时编辑运行代码.预览效果的代码交互组件. 使用此组件, 不论 vue 页面还是 Markdown 文档中 ...

  2. 基于开源方案构建统一的文件在线预览与office协同编辑平台的架构与实现历程

    大家好,又见面了. 在构建业务系统的时候,经常会涉及到对附件的支持,继而又会引申出对附件在线预览.在线编辑.多人协同编辑等种种能力的诉求. 对于人力不是特别充裕.或者项目投入预期规划不是特别大的公司或 ...

  3. angularjs学习总结(快速预览版)

    对html标签的增强 -> 指令 指令的本质是什么 声明的方式调用相应的脚本,实现一些操作,声明的所在的dom就是脚本的执行上下文? 自定义标签 -- 标签指令自定义属性 -- 属性指令特定格式 ...

  4. 盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k

    最近浏览 Github ,收藏了一些还算不错的 Java面试/学习相关的仓库,分享给大家,希望对你有帮助.我暂且按照目前的 Star 数量来排序. 本文由 SnailClimb 整理,如需转载请联系作 ...

  5. Android开源项目SlidingMenu本学习笔记(两)

    我们已经出台SlidingMenu使用:Android开源项目SlidingMenu本学习笔记(一个),接下来再深入学习下.依据滑出项的Menu切换到相应的页面 文件夹结构: watermark/2/ ...

  6. 盘点一下Github上开源的编程面试/学习相关的仓库

    转载自:JavaGuide 最近浏览 Github ,收藏了一些还算不错的 Java面试/学习相关的仓库,分享给大家,希望对你有帮助.我暂且按照目前的 Star 数量来排序. 本文由 SnailCli ...

  7. 开源框架.netCore DncZeus学习(三)增加一个菜单

    框架运行起来了,先尝试增加一个菜单. 本节增加一个菜单名字:公司管理,需要注意一点,所有的name都要保持一致,注意圈中部分.为了防止手敲代码出错,建议复制已有的代代码进行修改(比如这里用的Role页 ...

  8. WCF入门教程(四)通过Host代码方式来承载服务 一个WCF使用TCP协议进行通协的例子 jquery ajax调用WCF,采用System.ServiceModel.WebHttpBinding System.ServiceModel.WSHttpBinding协议 学习WCF笔记之二 无废话WCF入门教程一[什么是WCF]

    WCF入门教程(四)通过Host代码方式来承载服务 Posted on 2014-05-15 13:03 停留的风 阅读(7681) 评论(0) 编辑 收藏 WCF入门教程(四)通过Host代码方式来 ...

  9. 开源规则引擎 Drools 学习笔记 之 -- 1 cannot be cast to org.drools.compiler.kie.builder.impl.InternalKieModule

    直接进入正题 我们在使用开源规则引擎 Drools 的时候, 启动的时候可能会抛出如下异常: Caused by: java.lang.ClassCastException: cn.com.cheng ...

随机推荐

  1. unittest框架里的常用断言方法:用于检查数据

    1.unittest框架里的常用断言方法:用于检查数据. (1)assertEqual(x,y) 检查两个参数类型相同并且值相等.(2)assertTrue(x) 检查唯一的参数值等于True(3)a ...

  2. 回流&重绘

    浏览器加载解析页面:把HTML解析为DOM树,解析CSS生成CSSOM树,HTML DOM树和CSSOM树组合构建render树,首次触发回流和重绘后将页面结构信息发送给GPU进行绘制渲染. 回流:当 ...

  3. 浅谈倍增法求解LCA

    Luogu P3379 最近公共祖先 原题展现 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入格式 第一行包含三个正整数 \(N,M,S\),分别表示树的结点个数.询问 ...

  4. vue传值的几种方式

    props:适用于 父组件 ==> 子组件 通信 由父组件传值子组件在props中接收即可: (由父组件给子组件传递 函数类型 的props可实现 子组件 ==> 父组件 传递数据,较为繁 ...

  5. Vscode标题栏出现【不受支持】提示的完美解决方案

    安装Fix VSCode Checksums code --install-extension lehni.vscode-fix-checksums 打开命令面板,快捷键 Ctrl + Shift + ...

  6. 2分钟实现一个Vue实时直播系统

    前言 我们在不敲代码的时候可能会去看游戏直播,那么是前台怎么实现的呢?下面我们来讲一下.第一步,购买云直播服务 首先,你必须去阿里云或者腾讯云注册一个直播服务.也花不了几个钱,练手的话,几十块钱就够了 ...

  7. 基恩士的浓淡补正算法(Shading Correction Filter)的模拟实现。

    知道这个算法应该有很久了,主要当时在意2个事情,一个是这个名字的翻译是在是搞笑,第二是这个算法的效果.不过一直以来都十分好奇这个算法是怎么实现的.因为之前一直无法实际的用基恩士的软件平台用不同的图片去 ...

  8. SAP Smartforms 参数配置

    DATA : sf_name TYPE rs38l_fnam. DATA : sf_output_options TYPE ssfcompop. DATA : sf_control_parameter ...

  9. HMS Core音频编辑服务支持7种音频特效,助力一站式音频处理

    多媒体时代,音频作为内容传播中的重要形式,因其不受空间限制.认知负担小.声音元素多样化等特点,广泛应用于短视频制作.儿童在线教育.有声阅读.游戏等领域产品,在各种形式的音频呈现过程中,合理添加音效能够 ...

  10. 从Wannacry到WannaRen:螣龙安科带你深度分析勒索病毒原理

    从Wannacry到WannaRen:螣龙安科2020年4月7日,360CERT监测发现网络上出现一款新型勒索病毒wannaRen,该勒索病毒会加密windows系统中几乎所有的文件,并且以.Wann ...