从Go的基础语法开始讲起
一、首先第一个程序 Hello world
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
二、变量
1.声明变量
go是一门和c很相似的语言
go语言是变量是后值类型,声明变量要用var
一共有四种声明方式
一般方法如下
var 变量名字 类型 = 表达式
1. var a = "initial" // 没有说明类型会自动推导变量类型
2. var b, c int = 1, 2 // 声明的时候后置说明类型,并且赋值
3. d := true // 不需要使用var直接 变量名 := value
4. var e = false
在go语言中所有的变量都是默认0值,假设声明了变量没有赋值,int和float类型初值为0,string初值为"", bool类型为false
os.Open(FileName) 返回两个值第一个值是被打开的文件,
第二个值是内置error类型,如果error值为nil说明文件打开成功,如果不为nil则说明文件打开有问题,使用Fprintf与表示任意类型默认格式值的动词%v,向标准错误流打印一条信息
2.指针
指针存储的是另一个变量的地址,我们可以直接读或更新对应变量的值,而不需要知道该变量的名字
如果用“var x int”声明语句声明一个x变量,那么&x表达式(取x变量的内存地址)将产生一个指向该整数变量的指针,指针对应的数据类型是*int
指针被称之为“指向int类型的指针”。如果指针名字为p,那么可以说“p指针指向变量x”,或者说“p指针保存了x变量的内存地址”。
同时*p表达式对应p指针指向的变量的值。一般*p表达式读取指针指向的变量的值
简单来说就是&p取得一个变量的地址,*p获得这个变量的值,也可以使用*p去修改变量的值
x := 1
p := &x
fmt.Println(p) // 此时输出x的地址
fmt.Println(*p) // 此时输出x的值
*p = 2
fmt.Println(x) // 输出 2
在Go语言中,返回函数中局部变量的地址也是安全的。例如下面的代码,调用f函数时创建局部变量v,在局部变量地址被返回之后依然有效,因为指针p依然引用这个变量。
函数返回的是一个指针,相当于临时变量v的地址,p可以保存临时变量v的地址,fmt.Println(f() == f())会输出false是因为每次调用f()生成的v的地址都不相同
var p = f()
func f() *int {
v := 1
return &v
}
func main() {
fmt.Println(f())
fmt.Println(f())
fmt.Println(f() == f()) // 输出false
}
3.new函数
通过new(T)去创建一个T类型的匿名变量,初始值为T类型的零值,然后返回变量地址
p := new(int) // p, *int 类型, 指向匿名的 int 变量
fmt.Println(*p) // "0"
*p = 2 // 设置 int 匿名变量的值为 2
fmt.Println(*p) // "2"
new函数类似是一种语法糖,而不是一个新的基础概念。
一下两个方法有着相同的行为
func newInt() *int {
return new(int)
}
func newInt() *int {
var dummy int
return &dummy
}
三、变量赋值
赋值和c++的赋值方法没有区别
唯一有区别的是 ++ 和 -- 在go中++和--是与语句,不是表达式所以x = i ++是错误的
var i int
var x
x = i ++ //会报错
1.元组赋值
允许一次更新多个变量的值
x, y = y, x
a[i], a[j] = a[j], a[i]
最大公约数gcd
func gcd(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
求斐波那契数列fib
func fib(n int) int {
x, y := 0, 1
for i := 0; i < n; i++ {
x, y = y, x+y
}
return x
}