main 包中的main函数是程序的入口;java
1 逐个导入python
import "fmt"
import "math"
复制代码
2 分组导入linux
import (
"fmt"
"math"
)
复制代码
官方建议使用分组导入的方式数组
在 Go 中,若是一个名字以大写字母开头,那么它就是已导出的;在导入一个包时,你只能引用其中已导出的名字。任何“未导出”的名字在该包外均没法访问。闭包
例如math 包中的Pi是导出的,pi是未导出的,执行程序时math.pi会报错,而math.Pi能够正常运行函数
函数能够没有参数或接受多个参数;ui
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
复制代码
注意:当连续两个或多个函数的已命名形参类型相同时,除最后一个类型之外,其它均可以省略。spa
func add(x, y int) int {
return x + y
}
复制代码
上面的函数中线程
x int, y int
复制代码
被缩写为指针
x, y int
复制代码
函数能够返回任意数量的返回值。
func swap(x, y string) (string, string) {
return y, x
}
复制代码
var 语句用于声明一个变量或一个变量列表。
var c bool
var python, java bool
复制代码
只在函数内有效的变量相似于Java中的局部变量,使用:= 符号声明。
func main() {
k := 3
}
复制代码
注意::= 结构不能在函数外使用。
bool 布尔
string 字符串
int int8 int16 int32 int64 整形
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名,表示一个 Unicode 码点
float32 float64 浮点
complex64 complex128
注意:int, uint 和 uintptr 在 32 位系统上一般为 32 位宽,在 64 位系统上则为 64 位宽。 当你须要一个整数值时应使用 int 类型,除非你有特殊的理由使用固定大小或无符号的整数类型
能够使表达式 T(v) 将值 v 转换为类型 T。例如:
var i int = 42
var f float64 = float64(i)
复制代码
注意:Go 在不一样类型的项之间赋值时必需要显式转换。
常量的声明与变量相似,使用 const 关键字。
常量能够是字符、字符串、布尔值或数值。
常量不能用 := 语法声明。
const Pi = 3.14
复制代码
Go 只有一种循环结构:for 循环
for i := 0; i < 10; i++ {
sum += i
}
复制代码
i := 0 初始化语句 i < 10 条件表达式 i++ 后置语句
和Java很是像了。
初始化语句和后置语句也是可选的
for ; sum < 1000; {
sum += sum
}
复制代码
for {
}
复制代码
if 语句与 for 循环相似,表达式外无需小括号 ( ) ,而大括号 { } 则是必须的。
if x < 0 {
return sqrt(-x) + "i"
}
复制代码
if 语句能够在条件表达式前执行一个简单的语句,该语句声明的变量做用域仅在 if 以内。
if v := math.Pow(x, n); v < lim {
return v
}
复制代码
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
fmt.Printf("%s.\n", os)
}
复制代码
case 无需为常量,且取值没必要为整数。
没有条件的 switch 同 switch true 同样,一般用来代替较多的if-then-else。
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
复制代码
defer 语句会将函数推迟到外层函数返回以后执行。例如:
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
复制代码
结果为:
hello
world
复制代码
原理:推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
Go 拥有指针。指针保存了值的内存地址。类型 *T 是指向 T 类型值的指针。其零值为 nil。
var p *int
& 操做符会生成一个指向其操做数的指针。
i := 42
p = &i
星号操做符表示指针指向的底层值。
fmt.Println(*p) // 经过指针 p 读取 i 结果为42
*p = 21 // 经过指针 p 设置 i
fmt.Println(*p) //结果为21
相似于Java中的实体,一个结构体(struct)就是一组字段(field)。
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
复制代码
注意:结构体中的字段也能够经过指针来访问。
表达式:[n]T 表示拥有 n 个 T 类型的值的数组。
var a [10]int
复制代码
注意:数组的长度是其类型的一部分,所以数组不能改变大小。
切片为数组元素提供动态大小的、灵活的视角,在实践中,切片比数组更经常使用。
类型 []T 表示一个元素类型为 T 的切片。
切片经过两个下标来界定,即一个上界和一个下界,两者以冒号分隔:
a[low : high]
它会选择一个半开区间,包括第一个元素,但排除最后一个元素。
如下表达式建立了一个切片,它包含 a 中下标从 1 到 3 的元素:
a[1:4]
切片并不存储任何数据,它只是描述了底层数组中的一段。
更改切片的元素会修改其底层数组中对应的元素。
与它共享底层数组的切片都会观测到这些修改。
对于数组
var a [10]int 来讲,如下切片是等价的:
a[0:10]
a[:10]
a[0:]
a[:]
复制代码
切片的长度就是它所包含的元素个数,能够经过len(s)获取 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数,能够经过cap(s)获取。
切片的零值是 nil。
nil 切片的长度和容量为 0 且没有底层数组。
切片能够用内建函数 make 来建立,这也是建立动态数组的方式。
切片中能够包含其余切片。
Go 没有类。不过你能够为结构体类型定义方法。
方法就是一类带特殊的 接收者 参数的函数。
方法接收者在它本身的参数列表内,位于 func 关键字和方法名之间。
在此例中,Abs 方法拥有一个名为 v,类型为 Vertex 的接收者。
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
复制代码
注意:方法只是个带接收者参数的函数。
非结构体也可定义方法,例如:
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
复制代码
接口类型 是由一组方法签名定义的集合,接口类型的变量能够保存任何实现了这些方法的值。
Go 程(goroutine)是由 Go 运行时管理的轻量级线程。
go f(x, y, z)会启动一个新的 Go 程并执行
f(x, y, z)f, x, y 和 z 的求值发生在当前的 Go 程中,而 f 的执行发生在新的 Go 程中。
Go 程在相同的地址空间中运行,所以在访问共享的内存时必须进行同步。
信道是带有类型的管道,适合在各个 Go 程间进行通讯。你能够经过它用信道操做符 <- 来发送或者接收值。
ch <- v // 将 v 发送至信道 ch。
v := <-ch // 从 ch 接收值并赋予 v。(“箭头”就是数据流的方向。)
复制代码
和映射与切片同样,信道在使用前必须建立:
ch := make(chan int)
复制代码
默认状况下,发送和接收操做在另外一端准备好以前都会阻塞。这使得 Go 程能够在没有显式的锁或竞态变量的状况下进行同步。
信道能够是 带缓冲的。将缓冲长度做为第二个参数提供给 make 来初始化一个带缓冲的信道:
ch := make(chan int, 100)
复制代码
仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。