环境安装

输出语句

无论学那一门语言,首先先学该语言的输出语句。俗话说得好,输出"Hello, World!",代表你入门成功!!!

package main


import "fmt"


func main() {
  fmt.Println("Hello, World!")

接下来,一起学习go的基本语法,十分钟解决完战斗,走起!!!

Go语言关键字

首先先认识一下Go语言中关键字,心里有个印象,让初学者有个眼熟就行。记不住没关系,我会在下面语法反复提到。在这里之所以提出来,就是让你们看一下,看的看的就记住了。

关键字作用一级分类二级分类三级分类
var变量声明基本结构变量与常量-
const常量声明基本结构变量与常量-
package包声明基本结构包管理-
import包引用基本结构包管理-
func函数声明基本组件函数-
return函数返回基本组件函数-
interface接口基本组件自定义类型-
struct结构体基本组件自定义类型-
type定义类型基本组件自定义类型-
map基本组件引用类型-
range基本组件引用类型-
go流程控制并发-
select流程控制并发-
chan流程控制并发-
if流程控制单任务流程控制单分支流程
else流程控制单任务流程控制单分支流程
switch流程控制单任务流程控制多分支流程
case流程控制单任务流程控制多分支流程
default流程控制单任务流程控制多分支流程
fallthrough流程控制单任务流程控制多分支流程
for流程控制单任务流程控制循环流程
break流程控制单任务流程控制循环流程
continue流程控制单任务流程控制循环流程
goto流程控制单任务流程控制
defer流程控制延时流程控制

类型

数据类型

在 Go 编程语言中,数据类型用于声明函数和变量。

数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。

Go 语言按类别有以下几种数据类型:

类型长度默认值说明
bool1false
byte10uint8
int,uint4,80默认整数类型,依据目标平台,32或64
int8,uint810-128127,0127
int16,uint1620-215~(215)-1,0~(2^15)-1
int32,uint3240-231~(231)-1,0~(2^31)-1
int64,uint6480-263~(263)-1,0~(2^63)-1
float3240.0
float6480.0默认浮点数类型
string“”字符串,默认值为空字符串,而非NULL
array数组
struct结构体
interfacenil接口
functionnil函数
mapnil字典,引用类型
slicenil切片,引用类型
channelnil通道,引用类型

变量定义

在数学概念中,变量表示没有固定值且可改变的数。但从计算机系统实现角度来看,变量是一段或多段用来存储数据的内存。

作为静态类型语言,go变量总是有固定的数据类型,类型决定了变量内存的长度和存储格式。我们只能修改变量值,无法改变类型。

var关键字定义

关键字var用于定义变量,和C不同,类型被放在变量后面。若显式提供初始值,可省略变量类型,由编译器推断。

var X int // 自动初始化为零
var y = false // 自动推断为bool的类型

可一次性定义多个变量,类型可相同也可不相同。

var x,y int
var a,b = 100, "abc"

简短模式

变量定义时,除var关键字外,还可使用更加简短的变量定义和初始化语法。

package main


import "fmt"


func main() {
  x := 10 // 使用 := 进行定义并初始化
  fmt.Println(x) // 输出语句 10

使用简短模式的一些限制:

  • 定义变量,同时显式初始化。

  • 不能提供数据类型。

  • 只能用在函数内部,不能用在全局变量中。

多变量赋值

进行多变量赋值操作时,首先计算出等号右边值,然后再依次完成赋值操作。

package main


import "fmt"


func main(){
  x, y := 10, 20
  x, y = y+3, x+2  // 先计算等号右边值,然后再对x、y变量赋值
  fmt.Println(x, y) // 输出语句  结果为:23 12

常量

常量表示运行时恒定不可改变的值,通常是一些字面量。使用常量就可用一个易于阅读理解的标识符号来代替"魔法数字",也使得在调整常量值时,无须修改所有引用代码。

常量值必须是编译期可确定的字符、字符串、数字或布尔值。可指定常量类型,或由编译器通过初始化推断。

在go语言中,使用关键字const来定义常量。

const x, y int = 10, 20
const a,b = "迈莫coding", "欢迎小伙伴"

示例:

package main


import "fmt"


const (
   a, b string = "迈莫coding", "欢迎小伙伴"
)


func main() {
   fmt.Println(a,b) // 迈莫coding 欢迎小伙伴

iota关键字

Go中没有明确意思上的enum(枚举)定义,不过可以借用iota标识符实现一组自增常量值来实现枚举类型。

const (
  a = iota // 0
  b        // 1
  c        // 2
)

变量a、b、c的值分别为0、1、2,原因是因为使用iota进行自增时,后续自增值按照序递增。通俗点是每新增一行,iota值加一。

若在中途中断iota自增,则必须显示恢复,如下所示:

const (
  a = iota // 0
  b        // 1
  c = 100  // 100
  d        // 100 (与上一行常量值表达式一致)
  e = iota // 4 (恢复iota自增,计数包括c、d)
  f        // 5
)

运算符

运算符使用方式和其他语言基本一样,在这里就不一一介绍了。

package main
import "fmt"
func main() {
   var a int = 21
   var b int = 10
   var c int
   c = a + b
   fmt.Println(c) // 31
   c = a - b
   fmt.Println(c) // 11
   c = a / b
   fmt.Println(c) // 2
   c = a % b
   fmt.Println(c) // 1
   a++
   fmt.Println(a) // 22
   a=21   // 为了方便测试,a 这里重新赋值为 21
   a--
   fmt.Println(a) // 20
}

函数

函数就是将复杂的算法过程分解为若干较小任务,进行拆分,易于维护。函数被设计成相对独立,通过接收输入参数完成一段算法指令,输出或存储相关结果。因此,函数还是代码复用和测试的基本单元。

关键字func用于定义函数。

package main


import "fmt"


// 定义 Write函数 返回值有两个,一个为name,一个age为
func Write() (name string, age int) {
   return "迈莫coding", 1
}


// 定义 Read函数
func Read(name string, age int) {
   fmt.Println(name, " 已经 ", age, " 岁了")
}


func main() {
   Read(Write()) // 迈莫coding  已经  1  岁

条件语句和循环语句

条件语句

条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。

下图展示了程序语言中条件语句的结构:

package main


import "fmt"


func main() {
  x := 3
  
  if x > 5 {
    fmt.Println("a")
  } else if x < 5 && x > 0 {
    fmt.Println("b")
  } else {
    fmt.Println("c")
  }

循环语句

在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。

以下为大多编程语言循环程序的流程图:

package main


import "fmt"


func main() {
  for i := 0; i < 5; i++ {
    if i == 4 {
      continue
    } else if i == 5 {
      break
    }     
    fmt.Println(i)
  }

数据

数组

Go 语言提供了数组类型的数据结构。

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。

package main


import "fmt"


func main() {
  var arr1 [4]int // 元素自动初始化为零
  fmt.Println(arr1) // [0 0 0 0]
  
  arr2 := [4]int{1,2} // 其他未初始化的元素为零
  fmt.Println(arr2) // [1 2 0 0]
  
  arr3 := [4]int{5, 3:10} // 可指定索引位置初始化
  fmt.Println(arr3) // [5 0 0 10]
  
  arr4 := [...]int{1,2,3} // 编译器按照初始化值数量确定数组长度
  fmt.Println(arr4) // [1 2 3]
  
  t := len(arr4) // 内置函数len(数组名称)表示数组的长度
  fmt.Println(t) // 3

字符串

字符串默认值不是nil,而是""。

package main


import "fmt"


func main() {
  var str string
  str = "迈莫coding欢迎小伙伴"
  fmt.Println(str)

切片

切片(slice)本身不是动态数组或动态指针。只是它内部采用数组存储数据,当数组长度达到数组容量时,会进行动态扩容。

大白话就是切片功能和Java中的List集合类似,动态添加数据。不像数组(array)长度是固定的,需要事先知道数据长度。

初始化slice

x := make([]int, 1) // 通过make关键字进行slice初始化

示例

package main


import "fmt"


func main() {
    // 方式一
    a := make([]int,5) // 初始化长度为5的slice,默认值为零
    for i := 0; i <5; i++ {
       a = append(a, i)
    }
    a = append(a, 6)
    fmt.Println(a) // [0 0 0 0 0 0 1 2 3 4 6] 


    // 方式二    
    var a []int
    for i := 0; i < 5; i++ {
       a = append(a, i)
    }
    fmt.Println(a) // [0 1 2 3 4]

map字典

map字典也是使用频率比较高的数据结构。将其作为语言内置类型,从运行时层面进行优化,可获得更高效类型。

作为无序键值对集合,字典key值必须是支持相等运算符的数据类型,比如数字、字符串、指针、数组、结构体,以及对应接口类型。

map字典功能和Java中的map集合功能类似。

字典是应用类型,使用make函数或初始化表达语句来创建。

package main


import "fmt"


func main() {
   // 定义 变量strMap
   var strMap map[int]string
   // 进行初始化
   strMap = make(map[int]string)
   
   // 给map 赋值
   for i := 0; i < 5; i++ {
      strMap[i]  = "迈莫coding"
   }
   
   // 打印出map值
   for k, v := range strMap{
      fmt.Println(k, ":", v)
   }
  
  // 打印出map 长度
  fmt.Println(len(strMap))   

结构体struct

结构体(struct)将多个不同类型命名字段(field)序列打包成一个复合类型。

字段名必须唯一,可用"_"补位,支持使用自身指针类型成员。字段属性为基本数据类型。

学过Java就可以进行类比,结构体struct可以类比为Java中的类,结构体struct中字段属性可以类比为Java中类成员变量,结构体struct的方法可以类比为Java中类成员方法。

结构体(struct)语法如下:

type user struct {
  name string // 字段name 其数据类型为string
  age int // 字段age 其数据类型为int 
}

示例:

package main


import "fmt"


type user struct {
   name string
   age  int
}


// 结构体user Read方法
func (u *user) Read() string {
   return fmt.Sprintf("%s 已经 %d 岁了", u.name, u.age)
}


func main() {
   // 初始化
   u := &user{
      name: "迈莫coding",
      age:  1,
   }
   fmt.Println(u.name, "已经", u.age, "岁了")
   // 调用结构体user的 Read方法
   fmt.Println(u.Read()) // 迈莫coding 已经 1 岁

接口

接口代表一个调用契约,是多个方法声明的集合。

接口解除了类型依赖,有助于减少用户可视方法,屏蔽内部结构和实现细节。在Go语言中,只要目标类型方法集内包含接口声明的全部方法,就被视为实现了该接口,无须做显示声明。当然,目标类型可实现多个接口。

大白话,接口是多个方法声明的集合,若一个struct类实现接口中所有方法,即表示该类实现了指定接口。

语法

type user interface{
}

示例

package main


import "fmt"


// 定义接口 包含公共方法
type user interface{
  talking()
}


// 定义一个struct类
type memo struct{
}


// 实现接口user中方法talking
func (m *memo) talking() {
  fmt.Println("迈莫coding欢迎您...")
}


func main() {
  mm := memo{}
  mm.talking