go 基础
1、hello word
1、go 程序必须有一个 main 包
2、必须有main 主函数
3、需要导入一些包,比如 fmt
4、'{' 必须和方法名在同一行
5、导入的包必须在方法中使用,否则报错
package main
import "fmt"
func main() { // '{' 必须和方法名在同一行
fmt.Println("hello word")
}
2、基础数据类型(布尔类型、整型、浮点型、字符类型、字符串、复数类型)
可以包含数据的变量(或常量),可以使用不同的数据类型或类型来保存数据。使用 var 声明的变量的值会自动初始化为该类型的零值。类型定义了某个变量的值的集合与可对其进行操作的集合。
类型可以是基本类型,如:int、float、bool、string;结构化的(复合的),如:struct、array、slice、map、channel;只描述类型的行为的,如:interface。
结构化的类型没有真正的值,它使用 nil 作为默认值(在 Objective-C 中是 nil,在 Java 中是 null,在 C 和 C++ 中是 NULL 或 0)。值得注意的是,Go 语言中不存在类型继承。
函数也可以是一个确定的类型,就是以函数作为返回类型。这种类型的声明要写在函数名和可选的参数列表之后,例如:
func FunctionName (a typea, b typeb) typeFunc
float 类型 以及字符类型
float 类型,自动识别默认为 float64,比float32 更加精确
f:= 3.14
fmt.Printf("f type is %T\n",f) // f type is float64
// 字符类型 var ch byte
//ch = 97
// 格式化输出,%c 以字符方式打印,%d 以整数形式打印
//fmt.Printf("%c,%d \n", ch, ch) ch = 'a' // 字符 用单引号
fmt.Printf("%c,%d \n", ch, ch) // 大小写转换,大写 字母比 小写 字母数字 小 32
3、iota 枚举的 使用
1、iota 常量自动生成器,每个一行,自动累加1
2、iota 给常量赋值使用
const (
a = iota
b = iota
c = iota
)
fmt.Printf("a = %d, b = %d ,c = %d \n", a, b, c)
//3、iota 遇到const 重置为 0
const d = iota
fmt.Printf("d = %d\n", d) // d = 0
// 4、可以只写一个iota
const (
a1 = iota // 0
b1
c1
)
fmt.Printf("a1 = %d,b1 = %d,c1 = %d \n", a1, b1, c1)
// 5、如果在同一行,值都一样
const (
i = iota
j1,j2,j3 = iota,iota,iota
k = iota
)
fmt.Printf("i = %d,j1 = %d,j2 = %d,j3 = %d,k = %d\n",i,j1,j2,j3,k)
4、complex 复数
var t = 22 + 33i\
fmt.Println("t is ", t)
t is (22+33i)
fmt.Printf("t type is %T \n", t)
t type is complex128
通过内建函数,取得实部和虚部,
fmt.Println("real(t) = ", real(t), "imag(t) = ", imag(t))
real(t) = 22 imag(t) = 33
5、命令行输入
var tt int
fmt.Printf("请输入变量tt :")
// 阻塞等待用户输入\
//fmt.Scanf("%d",&tt) // 别忘了 &\
fmt.Scan(&tt)\
fmt.Println("输入的变量是tt:", tt)
6、类型起别名
type bigint int64
var a bigint
fmt.Printf(" a type is %T\n", a) // a type is main.bigint
// a type is main.bigint
type (
long int64
char byte
)
var b long = 77
var ch char = 'c'
fmt.Printf("b = %d,ch = %c\n", b, ch)
//b = 77,ch = c
fmt.Printf(" b type is %T\n", b)
//b type is main.long
fmt.Printf(" ch type is %T\n", ch)
//ch type is main.char
7 、for 循环使用
for 初始化条件;判断条件;条件变化
sum:=0
for i:=1;i <= 100 ;i ++ {
sum += i
}
fmt.Println("sum = ",sum)
8、range 的使用
// 通过 for 打印每个字符
abc := "abc"
for i := 0; i < len(abc); i++ {
fmt.Printf("str[%d] = %c\n", i, abc[i])
}
// 迭代打印每个元素,默认返回2个值, 一个是元素的位置,一个是元素本身
abc := "abc"
for i,data := range abc{
fmt.Printf("abc[%d] = %c\n",i,data)
}
for i := range abc{
fmt.Printf("str[%d] = %c\n", i, abc[i])
}
for i ,_ := range abc{ // 第二个返回值,默认丢弃
fmt.Printf("str[%d] = %c\n", i, abc[i])
}
9、函数
函数分为无参无返回值、有参有返回值、无参有返回值、有参无返回值四种
1、无参数无返回值的函数定义
func Wcc() {
a := 66
fmt.Println("a = ", a)
}
2、// 有参数 无返回值函数定义
一个参数
func wcc(a int) {
fmt.Println("a=", a)
}
二个参数
func wcc1(a int, b int) {\
fmt.Printf("a = %d,b = %d\n", a, b)\
fmt.Println("a + b = ", a+b)\
}
不定参数
// ...int 这样的类型,叫做不定参数类型\
// 不定参数,只能放在形参的最后一个参数\
func wcc2(args ...int) {
fmt.Println("len(args) = ", len(args))
for i := 0; i < len(args); i++ {
fmt.Printf("args[%d] = %d\n", i, args[i])
}
fmt.Println("===========================")
for i, data := range args {\
fmt.Printf("args[%d] = %d\n", i, data)\
}
}
3、无参数有返回值
// 无参数,有返回值,只有一 个返回值
// 有返回值的函数必须使用 return 返回
func t1() int {
return 2233
}
// 给返回值起一个变量名,go推荐写法
// 推荐写法\
func t2() (result int) {
result = 2233
return
}
// 多个返回值
func t3() ( a int,b int,c int) {
a,b,c = 111,222,333
return
}
func main() {
// 无参数,有返回值函数调用\
var a int
a = t1()
fmt.Println("a = ", a)
b := t1()
fmt.Println("b = ", b)
c:= t2()
fmt.Println("c = ",c)
d,e,f := t3()
fmt.Printf("d=%d,e=%d,f=%d\n",d,e,f)
}
4 、有参数有返回值
//求和, 实现 1+2 +3 ...... + 100
func test2(i int) (sum int) {
if i == 1 {
return 1
}
sum = i + test2(i-1)
return
}
func main() {
var sum int
sum = test2(100)
fmt.Println("sum = ", sum)
}
5、函数回调
有一个参数是函数类型,这个函数就是回调函数
package main
import "fmt"
type FuncType func(int, int) int
// 实现加法
func Add(a,b int) int{
return a + b
}
func Mul(a ,b int) int {
return a * b
}
func Calc(a, b int, fTest FuncType) (result int) {
fmt.Println("Clac")
result = fTest(a,b)
return
}
// 把 FuncType 不单独定义,直接写成匿名函数
func Calcc(a, b int, fTest func(int, int) (int)) (result int) {
fmt.Println("Clacc")
result = fTest(a,b)
return
}
func main() {
a := Calc(1,2,Add)
fmt.Println("a = ",a)
b := Calcc(1,2,Mul)
fmt.Println("b = ",b)
}
6、匿名函数和闭包
a := 10
str := "visco"
//匿名函数,没有名字,函数定义,还没调用
f1 := func() { // := 自动推导类型
fmt.Println("a = ", a)
fmt.Println("str = ", str)
}
f1()
// a = 10
//str = visco
// 定义匿名函数,同时调用
func() {
fmt.Printf("a = %d,str = %s\n", a, str)
}() //后面的 ()表示调用匿名函数本身,没参数就不传
//a = 10,str = visco
// 带参数的匿名函数
f2 := func(i, j int) {
fmt.Printf("i = %d,j = %d\n", i, j)
}
f2(2, 3)
// i = 2,j = 3
// 带参数的匿名函数
func(d, e int) {
fmt.Printf("d = %d,e = %d\n", d, e)
}(4, 5)
// d = 4,e = 5
// 匿名函数,有参数,有返回值
x, y := func(i, j int) (max, min int) {
if i > j {
max = i
min = j
} else {
min = i
max = j
}
return
}(3, 8)
fmt.Printf("x = %d,y = %d\n", x, y)
// x = 8,y = 3
10、闭包获取外部变量的特点
a := 2
str := "nike"
func() {
// 闭包以 '引用' 方式捕获外部变量,里面的改了,外面的变量也会改
a = 2233
str = "wcc"
fmt.Printf("内部a = %d,str = %s\n", a, str)
}() // () 代表直接调用
// a = 2233,str = wcc
fmt.Printf("外部a = %d,str = %s\n", a, str)
// a = 2233,str = wcc
因为这里闭包捕获变量是以 引用的方式,所以外部变量也会改变
11、闭包函数 的特点
先看普通的一个函数,调用后的结果
// 普通函数
func test3() int {
// 函数被调用时,x 才被分配空间,才初始化为 0
var x int // 初始化为 0
x++ // x=1
return x * x //函数调用完毕,x 自动释放
}
func main() {
fmt.Println(test3()) // 1
fmt.Println(test3())// 1
fmt.Println(test3())// 1
fmt.Println(test3())// 1
}
发现所有返回值都是 1,因为这里 x 每次调用完毕都会释放,然后每次都从 0 变成 1.
接下来用闭包函数实现
// 函数的返回值是一个匿名函数,返回一个函数类型
func t4() func() int {
var x int // 初始化为 0
return func() int {
x++ // 第一次 x =1,第二次 x=2,以此类推,每次 x 都没释放
return x * x
}
}
//返回值为一个匿名函数,返回一个函数类型,所以通过变量 f 来调用返回的匿名函数,f来调用闭包函数
//他不关心捕获的变量和常量是否超出了作用域
//所以只要闭包还在使用,变量就存在
f := t4()
fmt.Println(f())// 1
fmt.Println(f())// 4
fmt.Println(f())// 9
fmt.Println(f())// 16
12、defer 函数的使用
defer 函数,延迟调用,main函数 结束前调用
多个defer ,会按照 先进后出 的顺序执行,最后一个最先执行
无论中间发生什么错误,defer 都会执行
首先看一个简单的例子
func main() {
defer fmt.Println("aaaa")
fmt.Println("bbbb")
}
正常情况下,应该按照顺序打印 aaaa bbbb
但是定义了一个 defer 函数,延迟了 aaaa 的调用,先调用了 bbbb,再打印 aaaa
a := 1
b := 3
defer func(a, b int) {
fmt.Printf("a = %d,b = %d\n", a, b)
}(a, b) // a,b 先获取到上面的a ,b 的值1,3,只是最后才会去调用
a = 22
b = 33
fmt.Printf("a = %d,b = %d\n", a, b)
这个结果打印的是 a=22,b=33。a=1,b=3
这里先打印最后的 22 和 33,defer 函数会先获取到上面定义的 a b 变量,先拿到值,但没调用,只是在最后结尾的时候才会触发,最后打印出来 a=1,b=3
下面看另一种类似调用,
a := 1
b := 3
defer func() {
fmt.Printf("a = %d,b = %d\n", a, b)
}()
//a = 22,b = 33
a = 22
b = 33
fmt.Printf("a = %d,b = %d\n", a, b)
//a = 22,b = 33
这时候打印的 全是 a=22,b=33。以为上面 defer 没有传参 a b ,会在最后获取 a b 的值,因为最后才去调用,下面的 a b 值会直接覆盖上面的值,所以a=22,b=33
下面是多个 defer 的执行顺序,会按照先进后出的原则,最后一个最先执行。
fmt.Println(123)
defer fmt.Println("this is defer test")
defer func() {
fmt.Println(2233)
}()
结果会是
2233
this is defer test
123
13、获取命令行参数
package main
import "fmt"
import "os"
func main() {
// 接受用户传递的参数,都是以字符串方式传递
list:=os.Args
n:= len(list)
fmt.Println("长度是:",n)
for i:=0;i<n ;i++ {
fmt.Printf("list[%d] = %s\n",i,list[i])
}
//利用迭代同样打印输入的每个元素
for i,data:=range list{
fmt.Printf("list[%d] = %s\n",i,data)
}
}
我执行 go run 12获取命令行参数.go sss ddd aaa
以 空格 为单位,12获取命令行参数.go这个是第一个参数,sss 是第二个参数,ddd 是第三个参数,aaa 是第四个参数
执行结果 为:
长度是: 4
list[0] = /var/folders/5v/m892g1s92wn4zh2yd6_xwkth0000gn/T/go-build845588790/b001/exe/12获取命令行参数
list[1] = sss
list[2] = ddd
list[3] = aaa
14、局部变量
定义在{}里面的变量就是局部变量,只能在{}里面使用,
执行到定义变量的那句话,才开始分配空间,离开作用域自动释放
package main
import "fmt"
func main() {
// 定义在{}里面的变量就是局部变量,只能在{}里面使用
//执行到定义变量的那句话,才开始分配空间,离开作用域自动释放
{
i := 10
fmt.Println("i=", i) // i=10
}
if flag := 4; flag == 4 {
fmt.Println("flag = ", flag)
}
flag = 5 // undefined: flag
}
执行这段代码报错, go go run 13局部变量.go
command-line-arguments
./13局部变量.go:17:2: undefined: flag
会提醒 flag undefind,flag 在作用域定义了 值,离开{}作用域后自动释放了。
14、不同作用域,同名变量
package main
import "fmt"
var a byte // 全局变量
func main() {
var a int // 局部变量
//1、不同的 作用域,允许定义同名变量
//2、使用变量的原则,就近原则
fmt.Printf("%T\n", a) // int
{
var a float32
fmt.Printf("2 : %T\n", a) // float32
}
testc()
}
func testc() {
fmt.Printf("3 : %T\n", a) // uint8,也就是 byte,z这里只能使用全局的变量,局部的获取不到
}
15、
本作品采用《CC 协议》,转载必须注明作者和本文链接