导出名
任何以大写字母开头的变量或函数,都将在go中导出名称(exported names)。只有导出的函数和变量可以从其他包中访问。
Printf和Println的区别:
Printf : 只可以打印出格式化的字符串,可以输出字符串类型的变量,不可以输出整形变量和整形
Println :可以打印出字符串,和变量
:=的用法
只要:=左边有一个新变量都可以用:=,否则只能用=
命名返回值
可以在函数顶部定义待返回的变量名称,return优先级高
变量的初始化
变量声明可以包含初始值,每个变量对应一个。如果初始化值已存在,则可以省略类型;变量会从初始值中获得类型。
①可以定义类型,但不显式设置初始值
var a int
②可以设置初值,但不显式定义类型
var a = 1
③同时定义类型并初始化
var a int = 1
等同于在类型明确的地方用:=代替var进行声明
a := 1
b, c = "go",true
但这只能在函数体中使用
基本类型
变量声明也可以“分组”成一个语法块。
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的别名
rune // int32 的别名
// 表示一个 Unicode 码点
float32 float64
complex64 complex128
for
for 是 Go 中的 “while”
sum := 1
for sum < 1000 {
sum += sum
}
if
同 for 一样, if 语句可以在条件表达式前执行一个简单的语句。
func pow(x, n, lim float64) float64 {
v := math.Pow(x, n)
if v < lim {return v}
return lim
}
等价于
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n);v < lim {return v}
return lim
}
用牛顿法实现平方根函数
func Sqrt(x float64) float64 {
z1 := 1.0
z2 := z1 - ((z1*z1 - x) / (2*z1))
cnt := 1
for z1-z2>0.000001||z2-z1>0.000001{
z1 = z2
z2 -= (z1*z1 - x) / (2*z1)
cnt++
}
fmt.Println(cnt)
return z2
}
switch
Go 自动提供了每个 case 后面所需的 break 语句,除非以 fallthrough 语句结束,否则分支会自动终止。 Go 的另一点重要的不同在于 switch 的 case 无需为常量,且取值不必为整数。
没有条件的 switch 同 switch true 一样,这种形式能将一长串 if-then-else 写得更加清晰。
结构体
type Vertex struct {
X int
Y int
}
切片
切片为数组元素提供动态大小,比数组更为常用。更改切片的元素会修改其底层数组中对应的元素。
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[2:4]
结果输出:[5 7]
或另一种定义方式:
s := []int{2, 3, 5, 7, 11, 13}
结构体切片:
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
切片的长度就是它所包含的元素个数。len(s)
切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。cap(s)
(起始默认是前一个切片,长度按照当前的计算,不切尾)
var s []int
这样的切片s == nil
还可以用make创建切片:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
(len为0,所以b[1]
不存在,但是可以c := b[:2]
,然后对c[1]
进行修改)
二维切片
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
Range
for 循环的 range 形式可遍历切片或映射。在循环遍历切片时,每次迭代都会返回两个值。第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。
切片练习
func Pic(dx, dy int) [][]uint8 {
res := make([][]uint8,dy)
for i := 0;i<dy;i++{
for j := 0;j < dx;j++{
res[i] = append(res[i],(uint8)(i*j))
}
}
return res
}
映射
type Vertex struct {
Lat, Long float64//其中是
}
func main() {
m := make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
n := make(map[string]int)
n["num"] = 32
fmt.Println(n["num"])
这个make 函数会返回给定类型的映射,并将其初始化备用。不能像下面这样调用:
b := make([]int)
b[0] = 15
fmt.Println(b[0])
映射的文法与结构体相似
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
若顶级类型只是一个类型名(Vertex),你可以在文法的元素中省略它。
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
删除元素:
delete(m, key)
通过双赋值检测某个键是否存在:
elem, ok = m[key]
映射练习
func WordCount(s string) map[string]int {
m := make(map[string]int)
ss := strings.Fields(s)
for i := 0;i<len(ss);i++{
m[ss[i]]++
}
return m
}
函数值
函数也是值。可以像其它值一样传递。
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
函数的闭包
func adder() func(int) int {
sum := 0
return func(x int) int {//匿名函数
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()//相当于pos是前面return func这里的func名
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
斐波纳契闭包
package main
import "fmt"
// 返回一个“返回int的函数”
func fibonacci() func() int {
num := 0
pre := 0
return func() int{
if num == 0{
num = 1
}else{
tmp := num
num = num+pre
pre =tmp
}
return pre
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}