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 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!