1.for循环(没有别的循环)
多种形式:
形式1:
// a traditional "while" loop
for condition {
// ...
}
形式2:
for initialization; condition; post {
// zero or more statements
}
形式3:
// a traditional infinite loop
for {
// ...
}
形式4:
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
初始化语句必须是一条简单语句,即短变量声明,自增语句, 赋值语句,函数调用
2.变量声明
// 变量声明形式
s:= ""
var s string
var s = ""
var s string = ""
第一种形式,是一条短变量声明,最简洁,但只能用在函数内部,而不能用于包变量。第二种形式依赖于字符串的默认初始化零值机制,被初始化为""。第三种形式用得很少,除非同时声明多个变量。第四种形式显式地标明变量的类型,当变量类型与初值类型相同时,类型冗余,但如果两者类型不同,变量类型就必须了。实践中一般使用前两种形式中的某个,初始值重要的话就显式地指定变量的类型,否则使用隐式初始化
3.可变参数
func sum1(int, a...int){}
func sum2(nums...int){}
传参:
nums := []int{1,2,3,4,5}
sum1(1,nums...)
sum2(nums...)
4.变量
4.1 声明一组不同类型的变量
var b, f, s = true, 2.3, "four" // bool, float64, string
var f, err = os.Open(name) // os.Open returns a file and an error
4.2 短变量声明
简短变量声明语句中必须至少要声明一个新的变量
in, err := os.Open(infile)
// 在下面的代码中,第一个语句声明了in和err两个变量。在第二个语句只声明了out一个变量,
// 然后对已经声明的err进行了赋值操作。
out, err := os.Create(outfile)
4.3 指针
p指针指向变量x
指针对应的数据类型是*int
,指针被称之为“指向int类型的指针
指针是实现标准库中flag包的关键技术
x := 1
p := &x // p, of type *int, points to x
fmt.Println(*p) // "1"
*p = 2 // equivalent to x = 2
fmt.Println(x) // "2
4.4 new函数
返回的指针类型为*T
p := new(int) // p, *int 类型, 指向匿名的 int 变量
fmt.Println(*p) // "0"
*p = 2 // 设置 int 匿名变量的值为 2
fmt.Println(*p) // "2"
由于new只是一个预定义的函数,它并不是一个关键字,因此我们可以将new名字重新定义为别的类型。例如下面的例子:
func delta(old, new int) int { return new - old }
4.5 变量的生命周期
全局变量不回收
局部变量不可到达回收
5.赋值
如果map查找(§4.3)、类型断言(§7.10)或通道接收(§8.4.2)出现在赋值语句的右边它们都可能会产生两个结果,有一个额外的布尔结果表示操作是否成功:
v, ok = m[key] // map lookup
v, ok = x.(T) // type assertion
v, ok = <-ch // channel receive
它的规则是简单的:类型必须完全匹配,nil可以赋值给任何指针或引用类型的变量
6.类型
type Celsius float64 // 摄氏温度
type Fahrenheit float64 // 华氏温度
var c Celsius
var f Fahrenheit
Celsius(f) // 类型转换
对于每一个类型T,都有一个对应的类型转换操作T(x),用于将x转为T类型(译注:如果T是指针类型,可能会需要用小括弧包装T,比如(*int)(0)
)
命名类型还可以为该类型的值定义新的行为。这些行为表示为一组关联到该类型的函数集合,我们称为类型的方法集。
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
c := FToC(212.0)
fmt.Println(c.String()) // "100°C"
fmt.Printf("%v\n", c) // "100°C"; no need to call String explicitly
fmt.Printf("%s\n", c) // "100°C"
fmt.Println(c) // "100°C"
fmt.Printf("%g\n", c) // "100"; does not call String
fmt.Println(float64(c)) // "100"; does not call String
7.包和文件
8.作用域
1.内部声明屏蔽了外部同名的声明
2.局部作用域->全局作用域
3.if for switch 隐匿作用域
func main() {
x := "hello!"
for i := 0; i < len(x); i++ {
x := x[i]
if x != '!' {
x := x + 'A' - 'a'
fmt.Printf("%c", x) // "HELLO" (one letter per iteration)
}
}
}
// 在x[i]和x + 'A' - 'a'声明语句的初始化的表达式中都引用了外部作用域声明的x变量