go在ubuntu下的安装
- 下载安装包;
- 执行
tar -C /usr/local -xzf go<version.os-arch>tar.gz
解压; - 编辑
~/.profile
,加入一行export PATH=$PATH:/usr/local/go/bin
,注销用户,重新登录; - 创建文件
hello.go
,内容如下:
package main
import "fmt"
func main(){
fmt.Printf("hello, world\n")
}
- 同目录下执行
go run hello.go
,出现hello, world
说明成功。
Go工具选项
用法: go <command> [arguments]
commands:
- bug:报个bug
- build:编译包和依赖,会生成二进制文件
- clean:删除目标文件和缓存文件
- doc:显示包或记号的文档
- env:打印go的环境信息
- fix:通过调用go tool fix来将代码包中go文件使用的旧版本api更新
- fmt:通过调用gofmt来格式化代码
- generate:可以在代码中添加特殊注释,然后用工具来生成代码
- get:获取远程代码包和依赖
- install:构建并安装,没看懂
- list:列出包信息
- mod:用来维护模块,模块是包的上级结构
- run:运行,不会留下二进制文件
- test:用于测试
- tool:运行特定go工具
- version:打印版本
- vet:检查包中可能出现的错误,是go tol vet的简化版(或封装版?)
Sublime Text3配置
- 编译配置,保存为
Go Single File.sublime-build
,三个选项是仅build、终端运行、sublime运行。
{
"encoding": "utf-8",
"working_dir": "$file_path",
"shell_cmd": "go build \"$file\"",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"selector": "source.go",
"variants":
[
{
"name": "run in terminal",
"shell_cmd": "gnome-terminal -- bash -c 'go run \"$file_base_name\"&&read' "
},
{
"name": "run in sublime",
"shell_cmd": "go run \"$file_base_name\" "
}
]
}
- 程序入口,保存为
Go Entry.sublime-snippet
。
<snippet>
<content><![CDATA[
package main
import "fmt"
func main() {
${0:fmt.Println("I'll be the roundabout.\n")}
}
]]></content>
<tabTrigger>sa</tabTrigger>
<scope>source.go</scope>
</snippet>
简单规则
go语言的基础组成有:包声明、引入包、函数、变量、语句与表达式、注释。
- 第一行必须指明属于哪个包,
package main
的程序才可独立执行。 - 接下来是:
import"fmt"
表示引入包,其中fmt包含格式化输入输出函数。 func main()
是程序开始执行的函数,但如果有func init()
,会更先执行。- 注释:单行注释
//
,多行注释/* */
- fmt.Printf()、fmt.Println()用于打印到控制台。
- 标识符(常量、变量、类型、函数名等)以大写字母开头表示可被外部包代码使用,以小写字母开头表示不可被外部包使用。(好想法!)(下划线开头的,等待测试中)
- 每行的语句结尾不用添加分号,但分号仍可用于一行多个语句的分隔;
- 左大括号
{
不能单独放在一行(完了,要叛教)。
关键字
25个关键字/保留字:
for,while,continue,break
if,else,switch,case,fallthrough,default,select
func,return
var, const
package,import
interface,
defer,go,map,struct
chan,goto,
range,type
36个预定义标识符:
float32,float64,complex64,complex128,complex,real,imag
unit8,uint16,uint32,uint64
int8,int16,int32,int64
byte,rune,uint,int,unitptr
string,bool,true,false
nil,
iota,len,make,new,panic,print,println,cover,append,cap,close
数据类型
- 布尔型:bool,值只能是true或false
- 数字类型:
- 有符号整数int:8->64
- 无符号整数uint:8->64
- 实数:float32->64
- 复数:complex64->128,实部和虚部各占一半,通过real、imag、complex进行转换。
- 基于架构的类型:int、uint、uintptr
- 其他数字类型:byte(=uint8),rune(=int32)
- 字符串类型:string,由一系列字符组成,下标从0开始
- 派生类型:指针Pointer、数组、结构struct、Channel、函数、切片、接口interface、Map
变量
- 声明变量
var name1, name2 type [= val1, val2]
,默认值是零值:false、0、""、nil - 自动类型推导
var name [type] = val
- 声明语句
name1, name2 := val1, val2
,只能在函数体内使用,至少有一个未声明的变量 - 多类型声明
var(name1 type1 = val1; name2 type2)
,分号等价于换行 - 并行赋值:
a, b = b, a
,可用于交换两个变量 - 局部变量必须被使用,否则编译错误
_
是一个仅写变量,可以作为函数返回值的占位符等
基本类型属于值类型,变量在内存中存储值,复制时将内存中的值进行拷贝。
派生类型属于引用类型,变量在内存中存储一个地址,复制时只有引用被复制。
通过&可以获得变量的地址。
获得变量类型:reflect.TypeOf(name)
。或者fmt.printf("%T",name)
常量
将上面的var替换成const,即可定义常量。定义常量时需要指定初始值。
定义常量组时,如果不提供初始值,表示将使用上一行的表达式。
const(
qwq = 1
quq = 2
qaq
)
如果把const换成var会编译失败,因为qaq既没有指定类型,也没有指定值。
定义常量组时可以使用iota,表示当前行数
package main
import "fmt"
func main() {
const (
a = iota
b = 2
c = iota*iota
d
)
fmt.Println(a, b, c, d)
}
结果是0, 2, 4, 9
运算符
- 算术运算符:
+, -, *, /, %, ++, --
这里的++
和--
只能后置,而且不会返回变量,只有加1减1的效果,作为表达式使用。
只有完全相同的类型才能进行二元运算,比如int32和int64是不能加的… - 关系运算符:
==, !=, >, <, >=, <=
类型要求同上。 - 逻辑运算符:
&&, ||, !
,仅适用于bool类型 - 位运算符:
&, |, ^, <<, >>
,前三个位运算要求类型完全相同 - 赋值运算符:
=, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=
- 其他运算符:
&
取地址,*
定义时使用,用于定义指针,如var ptr *ubt
- 优先级:
* / % << >> &
>+ - | ^
>== != < <= > >=
>&&
>||
- 结合性:从左至右
条件语句
If
if [语句;] 条件语句 {
语句
}else if [语句;] 条件语句 {
语句
}else{
}
- 条件不需要用括号包含
- 大括号必须存在,即使只有一行
- 左括号必须和if或else一行
- 在
if
后条件语句之前可以添加一个语句,如果是声明语句,声明的变量作用域为整个if部分接下来的过程,小于外部变量,大于大括号内部变量。
Switch
switch var1 {
case val1:
...
case val2:
...
default:
...
}
- 不同的case之间不使用break分隔,因为执行一个case就会结束。
- 如果想要执行多个case,可以使用fallthrough关键字,强制执行下一个case。
- 支持多条件匹配:
case 1,2,3,4:
- 可以使用break退出
Type Switch
type switch用于判断interface变量中实际存储的变量类型,name.(type)
是type switch专属的一种方式。
switch x.(type){
case type1:
case type2:
default:
}
Select
与channel有关,看完之后再说。