Go语言从入门到实战 - Go语言中文社区

Go语言从入门到实战


最近在学习GO语言,看到了这个教程我觉得非常适合有点其它语言基础的人快速入门GO语言,推荐给大家。

先看下大概的介绍

蔡超目前在 Mobvista 担任技术副总裁兼首席架构师,之前的 9 年,曾在亚马逊(中国)、惠普等世界级 IT 公司担任过首席软件架构师。

拥有 15 年的软件开发经验,学习和使用过很多的编程语言,如:BASIC,Pasic,Perl,Python,C/C++,Java,Lisp,Haskel l 等,当然,也包括 Go 语言。 他在 Mobvista 带领团队,使用 Go 语言构建了国内最大同时也是全球排名前十的移动广告平台,这个平台每天处理着来自世界各地的超过 500 亿次请求,在 Go 语言方面有着丰富的实操经验。

本课程适合已经掌握如 C/C++ Java Python PHP 等其它一门或多门编程语言的学员。

  • Go语言是Google公司开发的一种静态型、编译型并自带垃圾回收和并发的编程语言。
  • Go语言不使用虚拟机,只有运行时(runtime)提供垃圾回收和goroutine调度等。
  • Go语言使用自己的链接器,不依赖任何系统提供的编译器、链接器。因此编译出的可执行文件可以直接运行在几乎所有的操作系统和环境中。
  • 从Go 1.5版本之后,Go语言实现自举,实现了使用Go语言编写Go语言编译器及所有工具链的功能。
  • Go语言可以利用自己的特性实现并发编译,并发编译的最小元素是包。从Go 1.9版本开始,最小并发编译元素缩小到函数,整体编译速度提高了20%。
  • Go语言的并发是基于goroutine,goroutine类似于线程,但并非线程。可以将goroutine理解为一种虚拟线程。Go语言运行时会参与调度goroutine,并将goroutine合理地分配到每个CPU中,最大限度地使用CPU性能。
  • 在Go语言中,自增操作符不再是一个操作符,而是一个语句。因此,在Go语言中自增只有一种写法:i++如果写成前置自增“++i”,或者赋值后自增“a=i++”都将导致编译错误。
  • 在多个短变量声明和赋值中,至少有一个新声明的变量出现在左值中,即便其他变量名可能是重复声明的,编译器也不会报错。
  • 布尔型无法参与数值运算,也无法与其他类型进行转换。
  • 切片发生越界时,运行时会报出宕机,并打出堆栈,而原始指针只会崩溃。
  • 变量、指针和地址三者的关系是:每个变量都拥有地址,指针的值就是地址。
  • 变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
    • 对变量进行取地址(&)操作,可以获得这个变量的指针变量。
    • 指针变量的值是指针地址。
    • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
  • “*”操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值;当操作在左值时,就是将值设置给指向的变量。
  • 堆分配内存和栈分配内存相比,堆适合不可预知大小的内存分配。但是为此付出的代价是分配速度较慢,而且会形成内存碎片。
  • 编译器觉得变量应该分配在堆和栈上的原则是:
    • 变量是否被取地址。
    • 变量是否发生逃逸。
  • ASCII字符串长度使用len()函数。
  • Unicode字符串长度使用utf8.RuneCountInString()函数。
  • ASCII字符串遍历直接使用下标。
  • Unicode字符串遍历用for range。
  • Go语言的字符串是不可变的。
  • 修改字符串时,可以将字符串转换为[]byte进行修改。
  • []byte和string可以通过强制类型转换互转。
  • 一般情况下,这个过程可以交给编译器,让编译器在编译时,根据元素个数确定数组大小。var team = [...]string{"hammer", "soldier", "mum"}“...”表示让编译器确定数组大小。上面例子中,编译器会自动为这个数组设置元素个数为3。
  • 从数组或切片生成新的切片拥有如下特性。
    • 取出的元素数量为:结束位置-开始位置。
    • 取出元素不包含结束位置对应的索引,切片最后一个元素使用slice[len(slice)]获取。
    • 当缺省开始位置时,表示从连续区域开头到结束位置。
    • 当缺省结束位置时,表示从开始位置到整个连续区域末尾。
    • 两者同时缺省时,与切片本身等效。
    • 两者同时为0时,等效于空切片,一般用于切片复位。
    • 根据索引位置取切片slice元素值时,取值范围是(0~len(slice)-1),超界会报运行时错误。生成切片时,结束位置可以填写len(slice)但不会报错。
  • 切片有点像C语言里的指针。指针可以做运算,但代价是内存操作越界。切片在指针的基础上增加了大小,约束了切片对应的内存区域,切片使用中无法对切片内部的地址和大小进行手动调整,因此切片比指针更安全、强大。
  • 切片是动态结构,只能与nil判定相等,不能互相判等时。
  • 切片已经被分配到了内存,但没有元素,因此和nil比较时是false。
  • 使用make()函数生成的切片一定发生了内存分配操作。但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。切片不一定必须经过make()函数才能使用。生成切片、声明后使用append()函数均可以正常使用切片。
  • append()函数除了添加一个元素外,也可以一次性添加很多元素。
  • Go语言中切片删除元素的本质是:以被删除元素为分界点,将前后两个部分的内存重新连接起来。
  • 大多数语言中映射关系容器使用两种算法:散列表和平衡树。
  • 散列表可以简单描述为一个数组(俗称“桶”),数组的每个元素是一个列表。
  • 根据散列函数获得每个元素的特征值,将特征值作为映射的键。如果特征值重复,表示元素发生碰撞。碰撞的元素将被放在同一个特征值的列表中进行保存。散列表查找复杂度为O(1),和数组一致。最坏的情况为O(n),n为元素总数。散列需要尽量避免元素碰撞以提高查找效率,这样就需要对“桶”进行扩容,每次扩容,元素需要重新放入桶中,较为耗时。
  • 平衡树类似于有父子关系的一棵数据树,每个元素在放入树时,都要与一些节点进行比较。平衡树的查找复杂度始终为O(log n)。
  • sort.Strings的作用是对传入的字符串切片进行字符串字符的升序排列。
  • Go语言中并没有为map提供任何清空所有元素的函数、方法。清空map的唯一办法就是重新make一个新的map。不用担心垃圾回收的效率,Go语言中的并行垃圾回收效率比写一个清空函数高效多了。
  • Go语言中的map在并发情况下,只读是线程安全的,同时读写线程不安全。
  • 也就是说使用了两个并发函数不断地对map进行读和写而发生了竞态问题。map内部会对这种并发操作进行检查并提前发现。
  • sync.Map有以下特性:
    • 无须初始化,直接声明即可。
    • sync.Map不能使用map的方式进行取值和设置等操作,而是使用sync.Map的方法进行调用。Store表示存储,Load表示获取,Delete表示删除。
    • 使用Range配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值。Range参数中的回调函数的返回值功能是:需要继续迭代遍历时,返回true;终止迭代遍历时,返回false。
  • sync.Map没有提供获取map数量的方法,替代方法是获取时遍历自行计算数量。sync.Map为了保证并发安全有一些性能损失,因此在非并发情况下,使用map相比使用sync.Map会有更好的性能。
  • 列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。
  • 在Go语言中,将列表使用container/list包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作。
  • list的初始化有两种方法:New和声明。两种方法的初始化效果都是一致的。
  • 列表与切片和map不同的是,列表并没有具体元素类型的限制。因此,列表的元素可以是任意类型。这既带来遍历,也会引来一些问题。给一个列表放入了非期望类型的值,在取出值后,将interface{}转换为期望类型时将会发生宕机。
  • Go语言规定与if匹配的左括号“{”必须与if和表达式放在同一行,如果尝试将“{”放在其他位置,将会触发编译错误。与else匹配的“{”也必须与else在同一行,else也必须与上一个if或else if的右边的大括号在一行。
  • 通过for range遍历的返回值有一定的规律:
    • 数组、切片、字符串返回索引和值。
    • map返回键和值。
    • 通道(channel)只返回通道内的值。
  • 对map遍历时,遍历输出的键值是无序的,如果需要有序的键值对输出,需要对结果进行排序。
  • 在Go语言中的switch,不仅可以基于常量进行判断,还可以基于表达式进行判断。
  • 函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段,其可以提高应用的模块性和代码的重复利用率。
  • Go语言支持普通函数、匿名函数和闭包,从设计上对函数进行了优化和改进,让函数使用起来更加方便。
  • Go语言的函数属于“一等公民”(first-class),也就是说:
    • 函数本身可以作为值进行传递。
    • 支持匿名函数和闭包(closure)。
    • 函数可以满足接口。
  • golang中,函数可以为单返回值或多返回值,当函数为多返回值时,需要使用括号对返回值列表进行约束;函数的返回值可以为不同类型,并且可以在定义时指定返回值的变量名,并且在函数体中进行显式赋值,在函数内return时,对于已经显式赋值的返回值,在return时可以不带参数,也可以将部分返回值放在return语句中,此时return语句需要写出完整的返回值列表。
  • 同一种类型返回值和命名返回值两种形式只能二选一,混用时将会发生编译错误。
  • 函数内的局部变量只能在函数体中使用,函数调用结束后,这些局部变量都会被释放并且失效。
  • Go语言中传入和返回参数在调用和返回时都使用值传递,这里需要注意的是指针、切片和map等引用型对象指向的内容在参数传递中不会发生复制,而是将指针进行复制,类似于创建一次引用。
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/fl_dream/article/details/88127864
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-13 12:59:10
  • 阅读 ( 1526 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢