Go语言学习
环境配置
使用yum install
使用命令sudo yum install -y golang
直接下载安装包
环境:腾讯云主机 Ubuntu 16.04
具体见官方文档。
- 首先下载安装包:
wget https://studygolang.com/dl/golang/go1.11.linux-amd64.tar.gz
(请自行选择要下载的安装包) - linux可以选择直接解压到/usr/local中,
sudo tar -C /usr/local -xzf go1.11.linux-amd64.tar.gz
,会在目标目录建立一个go的文件树,安装完成一半 - 使用
vim ~/.bashrc
打开配置文件,然后输入export PATH=$PATH:/usr/local/go/bin
配置环境变量,使用source ~/.bashrc
刷新环境变量。 - 因为我用的是vim,所以安装就到此为止了。
环境2:本地虚拟CentOS主机
- 使用
sudo yum install golang
安装go - 设置环境变量,我用的是
~/go
作为工作空间,环境变量为export GOPATH=$HOME/go
与export PATH=$PATH:$GOPATH/bin
,与ubuntu不同,用户配置文件为~/.profile
,同样是使用source ~/.profile
刷新环境变量。
验证安装是否成功
在默认工作区(linux下为~/go
)下创建/src/hello,并写下下面代码:
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
然后尝试编译go build
,如果没有错误信息,尝试运行./hello
。如果看到hello,world
,则安装成功。
如果想要改变工作区位置,看这里。
与远程库关联
- 首先查看用户主目录下是否存在.ssh目录。没有的话,使用命令
ssh-keygen -t rsa -C "youremail@mail.com"
来创建SSH Key,然后将.ssh目录下的id_rsa.pub文件里的公约复制,在Github界面Settings的SSH and GPG Keys界面下,点击SSH Keys上的Add new并粘贴,取个Title,再确定。 - 使用
git init
创建本地仓库,然后使用git remote add origin git@github.com:wtysos11/sysu-goLearning.git
完成远程库关联。 - 使用
git commit
提交第一次操作,然后使用git push origin -u master
把主分支提交上远程库。
官方教程
快速入门
使用菜鸟教程进行快速入门,用作建立整体印象。要想细致学习推荐官方文档的language specification,挺好的,就目前而言比我看到的绝大多数资料讲的都要清楚有用,但是太长了,我还没看完老师就发了石墨文档,就先不写了。
数据类型
没太多好说的,比较类似于java,略过。
string近似于常量,不能够使用下标访问改变内容。
变量
变量声明有三种方式,一种是使用var identifier type
的形式声明后,使用=
进行变量赋值;一种是省略前一种中的type,让编译器自行判断类型;还有一种是使用:=
进行赋值,但是要求左侧的变量之前没有被声明过,不然会导致编译错误。
go的多变量赋值可以使用类似于Python的形式,即vname1,vname2,vname3 = v1,v2,v3
,会给每个变量进行分别赋值。
go与C++类似,存在值类型和引用类型,以及指针等概念。
可以使用const声明常量
比较特殊的是iota,即特殊长安令,在const关键字出现时被设为0,const中没新增一行常量就会计数一次,常规用法如下:
const(
a = iota
b = iota
c = iota
)
这样子与a=0,b=1,c=2
等价。还有一些比较厉害的操作,我也讲不清楚,需要自行查阅相关文档。虽然我觉得大部分人也不会用就是了。
运算符
C系列,略过
条件语句
注意左大括号{
不能单独成行,不然会有编译错误。
switch语句中的case可以为任意类型,而不是像C一样需要能够转化为整形才能使用。形式类似,但是不用加break,一旦匹配到一个case后会默认退出。如果加上fallthrough关键字后会继续往下进行。可以使用break关键字。
其中switch语句可以使用type-switch来判断摸个interface变量中实际存储的变量类型,需要自行查阅。
select:我也没用过。
循环语句
for语句相当于C语言不加左右括号的版本,两个分号如果省略的话与while是等价的。存在Goto,类似于python中的版本,可以跳转到标记行。但是break和continue是C中的,只能在当前循环进行操作(应该)
函数
格式:
func function_name([parameter list]) [return_types]{
}
其中func为关键字,后面分别是函数名,参数列表和返回类型。需要注意的是,返回类型可以为多个,也就是说可以同时返回多个值。
函数传参方式与Verilog和python类似,除了按照顺序传参,还可以直接使用函数中的变量名称进行传参。
方法:
格式
func (variable_name variable_data_type) function_name([parameter list]) [return_types]{
}
就是多了前面那个,表示是某个结构体的方法。
数组
声明类似与java看,格式:var variable_name[SIZE] variable_type
,多维数组直接使用多个[]
即可。可以使用{}
进行初始化,如var balance = [5]float32{1000.0,2.0,3.4,7.0,50.0}
,如果[]
中没有数字,会按照后面元素的个数来设置数组的大小。
使用下标来访问数组元素,向函数传递数组也是与java类似,即在参数列表中输入形为param [10]int
,其中数组大小的省略与否与C类似。
指针
与C类似,目前还没看出有什么不同的,初学阶段可以默认相同。
结构体
go没有面向对象的特性,结构体只是不同类型数据的有序集合。
需要使用type和struct来定义结构体,如:
type struct_variable_type struct{
member definition
}
如前所述,可以为结构体声明方法。
结构体赋值与C++等类似,即variable_name := struct_variable_type {value1,...}
或是variable_name:=struct_variable_type{key1:value1,...}
切片(slice)
slice是对数组的抽象,它是基于实际存在数组的。
因为Go数组长度不可改变,所以会有问题。slice可以改变元素的数量。
可以声明一个未知大小的数组来定义切片,如:var identifier []type
,或是使用make函数var slice1 []type = make([]type,len)
,也可以指定容量,容量大小为make的第三个参数(可选)
初始化与数组一样,可以如python和js以及matlab等用:
进行范围访问。len()方法获取长度,cap()方法获取切片的最大值(到达最大值后可以创建新的切片然后使用copy()方法进行转移),append()方法用于追加新的元素
范围(range)
类似与python中的enumerate,range可以对一个数组产生一个元组迭代序列,即
nums := []int{2,3,4}
sum := 0
for _,num := range nums{
sum += num
}
其中_
为空白占位符,类似与haskell,在这里表示的是忽略index值,得到的num即为元素的值。通过这一操作,可以实现数组求和。
Map
无序的键值对集合,与C++STL中的同名结构以及python中的dict类似。
使用内建函数make可以创建map
var map_variable map[key_data_type]value_data_type
map_variable := make(map[key_data_type]value_data_type)
使用delete函数删除键对应的值。
类型转换
与C++等类似,使用type_name(expression)
可以将expression中的值转换为type_name的类型。
接口
一种数据类型,可以将所有具有共性的方法定义在一起。其他类型只要实现了这些方法就是实现了这个接口
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
错误处理
error类型是一个接口类型,定义为
type error interface{
Error() string
}
与node.js类似,go的函数会与error对象相关联,不过js是在回调函数的第一个参数,error是返回值的第二个参数
读书记录
Cloud Native Go : 构建基于Go和React的云原生Web应用与微服务的读书记录,方便日后复习
1.云之道
cloud native:明确地关注应用而不是人和设计哲学,并且依赖于原始的“12要素法则”来定义和描绘应用程序。
云之道的优点
云之道改变了程序员对于软件开发的看法,把他们从重复添加功能、部署并祈祷其正常运行的艰难时刻中解脱出来,使软件开发再次成为乐趣。
规则:
- 遵循简单。质疑一切事物似乎违背简单性,如无必要,不应额外添加新的复杂流程;质疑每个工具是否必要;质疑所有的代码是否过于复杂以至于无法阅读。
- 测试优先,测试一切。测试提供信心,信心战胜对未知的恐惧;使用单元测试可以让信心指数上升。
- 尽早发布,频繁发布。将每次代码提交都当作潜在的生产发布,并通过持续交付流水线进行部署。
- 自动化一切。任何每天做的超过一次的事情,都适合自动化;流程中任何时常重复的部分,如果不能被按钮或脚本所取代,那么就属于复杂、脆弱或两者兼有之的部分。
- 建立服务生态系统。任何事物都是服务,包括应用。(微服务遵循了单一责任原则SRP,即源于面向对象的设计模式,一个服务只负责一个功能)
使用GO的原因:
- 简单
- 开源
- 易于自动化和IDE自动化
2.开始
配置环境
Mac需要安装Homebrew。
安装Mercurial和Bazaar(第三方Go包的来源,这两个都是版本控制系统)
实操记录:我在使用腾讯云提供的Ubuntu14.04LTS通过sudo apt-get install bazaar
安装bazaar时反馈没有这个包,根据官方的说明,应该使用apt-get install bzr
命令进行安装。
Mercurial的关联命令是hg,bazaar的关联命令是bzr。
可以通过go get命令从github上获取代码。
3.Go入门
使用基本函数
GO并不是面向对象的语言,GO中没有类,只有函数,这些函数的可见性由包的范围以及函数是否可以导出决定。
Go中可以实现完全的柯里化(把接受多个参数的函数变为接受一个参数的函数,并且返回接受其他参数和返回结果的新函数)
使用结构体
GO中的结构体只是字段的类型化集合,可以嵌套使用,也可以创建匿名结构体。
从type关键字开始,例如
type person struct{
name string
age int
}
可以使用不同的方式创建结构体,下面的代码都可以用来创建一个person结构体
var p = person{}
var p2 = person{"bob",21}
var p3 = person{name:"bob",age:21,}
或者在person前加&
也是可以的,会创建一个指向person结构体的指针。
第一行表示如何创建一个空的结构体,第二行表示通过定义字段的顺序使我们可以顺序地赋初始值。第三行允许我们以任何我们喜欢的顺序为字段赋值,因为它标明了字段的名称(类似于python)
介绍Go接口
向结构体添加方法
可以使用结构体(实际上几乎是任何类型)来锚定方法,这意味着可以拥有专门用于结构体的函数。
注意:如果名称与数据类型匹配,则不必重复声明两次,比如这样:
type attacker struct{
attackpower int
dmgbonous int
}
type sword struct{
attacker
twohanded bool
}
下面使用Go的语法来为结构体添加Wield方法
func (s sword) Wield() bool{
fmt.Println("You've wielded a sword!")
return true
}
Go中的接口动态类型检查
可以使用以下的简单代码声明一个指示某物是武器的接口:
type weapon interface {
Wield() bool
}
与其他语言不同的是,go中不必去声明一个结构体或者其他类型是一个武器,它能够凭借Go是否能够在一定范围内找到指定签名的方式自动被识别。
现在可以创建下面的函数:
func wielder (w weawpon) bool{
fmt.Println("Wielding ...")
return w.Wield()
}
现在就可以把sword变量传给wielder函数了。
因此只要类型满足一个接口,它就可以在任何使用该接口的地方使用。(大概就是我要一个修空调的人,不管是空调师傅还是物业阿姨,只要能修都是可以的)
创建自有包
导出函数和数据
软件包是Go中的一个访问范围单位,虽然没有OOP中的成员访问关键字,但是仍然可以控制代码的可见性。我们在Go中创建的任何以小写字母开头的类型(或函数)都被认为是包所私有的或者没有导出的。我们创建的任何以大写字母开头的类型都会被导出,任何使用该包的人都可以看到。
创建包
首先创建如下没有的目录$GOPATH/src/github.com/cloudnativego/go-primer/npcs
,这意味着将在这个目录下工作。
按照惯例,许多软件开发人员更喜欢创建一个types.go文件,其中包含要由软件包使用或导出的类型,例如以下这个。
package npcs
// Power describes the attack and defense power of the NPC
type Power struct {
Attack int
Defense int
}
// Location describes where in the virtual world an NPC exists
type Location struct {
X float64
Y float64
Z float64
}
// NonPlayerCharacter represents metadata for an in-game creature
type NonPlayerCharacter struct{
Name string
Speed int
HP int
Power Power
Loc Location
}
所有向包使用者暴露的方法会放在一个名为npcs.go的单独文件中:
package npcs
import (
"fmt"
"math"
)
func (loc Location) String() string{
return fmt.Sprintf("(%f,%f,%f)",loc.X,loc.Y,loc.Z)
}
...
所有的导出函数都需要以大写字母开头,同时它们所操作的结构体和字段也已经被导出了。
创建完这个子包之后,就可以在客户端应用程序中使用它了。