一、变量定义

1.1 Var定义变量

var name string = "zhangsan" 
var age int = 21 
var isOk bool bool

1.2 类型推导变量定义

在函数内部,可以使用更简略的 := 方式声明并初始化变量

// 变量名 := 表达式 
n := 10 
var age = 18

1.3 一次定义多个变量

package main

import "fmt"

func main() {
  var username, sex string
  username = "张三"
  sex = "男"
  fmt.Println(username, sex)
}

1.4 批量声明变量

package main

import "fmt"

func main() {
  var (
    a string
    b int
    c bool
  )
  a = "张三"
  b = 10
  c = true
  fmt.Println(a, b, c)
}

二、常量定义

2.1 常量

声明了 pi 和 e 这两个常量之后,在整个程序运行期间它们的值都不能再发生变化了

const pi = 3.1415 
const e = 2.7182 

// 多个常量也可以一起声明 
const ( 
  pi = 3.1415 
  e = 2.7182 
)

2.2 同时声明多个变量

const ( 
  n1 = 100 
  n2
  n3 
)
// 上面示例中,常量 n1、n2、n3 的值都是 100

三、Fmt包

3.1 Println

  1. 一次输入多个值的时候 Println中间有空格

  2. Println会自动换行,Print不会

fmt.Println("zhangsan", "lisi", "wangwu") // zhangsan lisi wangwu

3.2 Print

  1. 一次输入多个值的时候 Print没有 中间有空格

  2. Print不会自动换行

 fmt.Print("zhangsan", "lisi", "wangwu")   // zhangsanlisiwangwu

3.3 Printf

Printf是格式化输出,在很多场景下比Println更方便

fmt.Printf("%s 今年 %d 岁", name, age) // zhangsan 今年 20 岁 }

3.4 Sprintf

fmt.Sprintf 函数用于将格式化的字符串和其他值组合成一个新的字符串。与 Printf 不同,Sprintf 不会直接输出结果,而是将结果返回为一个新的字符串。

name := fmt.Sprintf("%v", "你好")
fmt.Println(name)

四、Init函数与main函数

4.1 init函数

go语言中 init函数用于包 (package) 的初始化,主要特征如下:

  1. init函数是用于程序执行前做包的初始化的函数,比如初始化包里的变量等

  2. 每个包可以拥有多个init函数

  3. 包的每个源文件也可以拥有多个init函数

  4. 不同包的init函数按照包导入的依赖关系决定该初始化函数的执行顺序

  5. init函数不能被其他函数调用,而是在main函数执行之前,自动被调用

4.1.1 包的执行顺序

全局声明 ——> init() ——> main()

4.2 main函数

Go语言程序的默认入口函数(主函数):func main(),函数体用{}一对括号包裹

func main(){ 
    //函数体 
}

4.3 init对比main函数

相同点

两个函数在定义时不能有任何的参数和返回值,且Go程序自动调用。

不同点

  1. init可以应用于任意包中,且可以重复定义多个。

  2. main函数只能用于main包中,且只能定义一个。

  3. 对同一个go文件的 init() 调用顺序是从上到下的。

  4. 对同一个package中不同文件是按文件名字符串比较从小到大顺序调用各文件中的 init() 函数。

  5. 对于不同的 package ,如果不相互依赖的话,按照main包中"import的后调用"的顺序调用其包中的init()`

  6. 如果 package存在依赖,则先调用最早被依赖的 package中的 init() ,最后调用 main函数。

四、命名规范

Go是一门区分大小写的语言。命名规则涉及变量、常量、全局函数、结构、接口、方法等的命名。

任何需要对外暴露的名字必须以大写字母开头,不需要对外暴露的则应该以小写字母开头。当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Analysize,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的public);命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的private

4.1 文件命名

尽量采取有意义的文件名,简短,有意义,应该为小写单词,使用下划线分隔各个单词。例如:create_user.go

4.2 结构体命名

采用驼峰命名法,首字母根据访问控制大写或者小写struct 申明和初始化格式采用多行,例如下面:

type MainConfig struct {
  Port string `json:"port"` 
  Address string `json:"address"`
}

4.3 变量命名

变量名称一般遵循驼峰法,首字母根据访问控制原则大写或者小写

  • 可访问的变量命名:User,Port

  • 内部访问的变量:user,port

4.4 常量命名

常量命名通常采用全部大写的方式,并使用下划线分隔单词,以表示其常量的性质。例如:MAX_VALUEMIN_LIMIT等。

4.5 函数命名

函数命名一般采用驼峰法,首字母根据访问控制原则大写或者小写。例如:GetDataProcessData等。

4.6 接口命名

接口命名与函数命名类似,采用驼峰法。首字母根据访问控制原则大写或者小写,例如:DataProviderDataProcessor等。

4.7 包命名

包的命名应该采用简短且有意义的名称,通常使用小写字母。例如:utilsdatabase等。

五、defer函数

5.1 defer运用及思想

defer语句采用的设计思想是后进先出(LIFO, Last In First Out)的栈式结构,也就是说,最后声明的defer语句会最先执行

  1. 关键字 defer 用于注册延迟调用

  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理

  3. 多个defer语句,按先进后出的方式执行,谁离return近谁先执行

  4. defer语句中的变量,在defer声明时就决定了

package main

import "fmt"

func Func() {
  defer fmt.Println("defer2")
  fmt.Println("func")
  defer fmt.Println("defer1")
}

func main() {
  defer fmt.Println("defer4")
  Func()
  defer fmt.Println("defer3")
}

执行顺序

func
defer1
defer2
defer3
defer4

5.2 defer坑点

deferi修改返回值,如果是返回值带名字的则defer时能够修改成功,当不带名字时defer返回不成功

package main

import "fmt"

func DeferRuturn() int {
    a := 0
    defer func() {
        a = 1
    }()
    return a
}

func DeferRuturn2() (a int) {
    a = 0
    defer func() {
        a = 1
    }()
    return a
}

func main() {
    fmt.Println(DeferRuturn()) // 0
    fmt.Println(DeferRuturn2()) // 1
}