二、Go语言基础入门——Go基础语法与使用

前言

最近买了两本书准备学习一下Go语言,其中一本是《Go语言高并发与微服务实战》另外一本是《Go Web编程实战派》,第一本是为了深入了解一下Go语言在高并发中的魅力,买第二本的原因是因为刚刚从Java转到Go语言,所以想更快的学习一些工作中可能接触到的Go Web相关的知识。

众所周知,Go语言是Google于2009年开源的一门编程语言,原名GoLanguage也叫Golang。它可以在不损失应用程序性能的情况下极大地降低代码的复杂度。相比较其他编程语言,它具备了简洁、快速、安全、并行、有趣、开源、内存管理、数组安全、编译迅速等等一些列特点。

话不多少,我会先学习《Go Web编程实战派》这本书,跟随我一起走进Go语言学习的海洋吧!!!

基础语法

我们以及完成了Go语言的第一个程序,接下来本章博客将从Go语言的基础语法以及使用方面进行学习,虽然这些知识对于有其他语言开发经验的同学很简单,但我相信还还会从中发现更多知识点。

行分隔符

在Go语言中,并不需要像Java、PHP等语言那样需要在一行语句的最后使用分号结尾,因为这些工作编译器已经帮我们完成了。但是如果在同一行有多条语句,那就必须使用分号进行分隔。但是这种方式在实际开发中并不鼓励书写哦!

注释

注释分为单行与多行,格式如下

单行注释:单行注释是最常见的注释形式,可以在任何地方进行使用。

//单行注释

多行注释:也被称之为“块注释”。

/*
多行注释

多行注释
*/

标识符

标识符通常用来对变量、类型等程序实体进行命名。一个标识符实际上就是一个或者多个字符、数字、下划线组成的。第一个字符不能为数字或者Go的关键字。

正确命名:product、user、add、user_name、abc_123、resultValue、_tmp、k
错误命名:switch(Go语言关键字)、3ab(以数字开头)、c-d(运算符不允许)

字符串连接

Go语言可以通过加号实现字符串拼接,示例如下:

package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello " + "World")
}

关键字

在Go语言中有25个关键字或保留字

关键词如下

关键字关键字关键字关键字关键字
continueforimportreturnvar
constfallthroughifrangetype
chanelsegotopackageswitch
casedefergomapstruct
breakdefaultfuncinterfaceselect

最新版本Go语言中还有30几个预定义标识符,可以按照以下划分:

常量相关预定义标识符:true、false、iota、nil

类型相关预定义标识符:int、int8、int16、in32、int64、uint、uint8、uint16、uint32、uint64、uintpr、float32、float64、complex128、complex64、bool、byte、rune、string、error

函数相关预定义标识符:make、len、cap、new、append、copy、close、delete、complex、reat、image、panic、revover

变量

声明

Go语言是静态强类型语言,因此变量是有明确类型的,编译器也会检查变量类型的正确性。当一个变量被声明后,系统会自动赋予它该类型的零值或者空值(int->0、float->0.0、bool->false、string->空字符串、指针类型->nil)。变量的命名规则依旧遵循“驼峰”命名法。变量的声明可以分为标准格式、批量格式、简短格式这三种形式。

标准格式

var 变量名 变量类型

变量声明以var开头,中间是变量名 后面是变量类型

批量格式

var(

age int

name string

balance float32

简短格式

名字 := 表达式

需要注意,简短模式有一下的限制

只能用来定义变量,同时会显式初始化

不能提供数据类型

只能用在函数内部,即不能用来声明全局变量

赋值

给单个变量赋值

var 变量名 [类型] = 变量值

eg

var name string = “zhuangyan”

var name = “zhuangyan”

name := “zhuangyan”

给多个变量赋值

var(

​ 变量名1 (变量类型) = 变量值1

​ 变量名2 (变量类型) = 变量值2

​ …

)

或者

var 变量名1,变量名2,变量名3 = 变量值1,变量值2,变量值3

或者

变量名1,变量名2,变量名3 := 变量值1,变量值2,变量值3

变量作用域

Go语言变量可以分为局部变量和全局变量。

局部变量:在函数体中被声明的变量被称为局部变量,作用域自在函数体内。

package main

import "fmt"

func main() {
   //声明局部变量
   var local1, local2, local3 int

   //初始化参数
   local1 = 1
   local2 = 2
   local3 = 3

   fmt.Printf("local1 = %d, local2 = %d ,local3 = %d", local1, local2, local3)
}

运行结果
local1 = 1, local2 = 2 ,local3 = 3

全局变量:在函数体外声明的变量被称为全局变量。全局变量可以在整个包甚至在外部包(被导出后)中使用,也可以在任何函数中使用。全局变量和局部变量的名称可以相同,但是函数内部的局部变量会被优先考虑。

package main

import "fmt"

//声明全局变量
var global int
var local3 int = 333

func main() {
	//声明局部变量
	var local1, local2, local3 int

	//初始化参数
	local1 = 1
	local2 = 2
	local3 = 3
	global = 4

	fmt.Printf("local1 = %d, local2 = %d ,local3 = %d, global = %d", local1, local2, local3, global)
}

运行结果
local1 = 1, local2 = 2 ,local3 = 3, global = 4

常量

常量的声明

Go语言的常量使用关键字const声明。常量实在编译时才被创建,即便声明在函数内部也是如此,并且只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。由于编译期有限制,声明常量的表单时必须为能被编译器求值的常量表达式。格式如下

const 常量名 [类型] = 常量值

或者

const(

​ 常量名1 [类型] = 常量值1

​ 常量名2 [类型] = 常量值2

)

eg

正确做法:const pi = 3.14159 、 const c1 = 5/2

错误做法:const url = os.GetEnc(“url”) 错误原因:os.GetEnc(“url”) 只有在运行期才能知道返回结果

常量生成器iota

常量声明可以使用常量生成器iota初始化。iota用于生成一组以相似规则初始化的常量,但是不需要每一行进行初始化表达式。可以在const声明语句的第一行使用iota,之后美增加一行iota会加1,并且每出现一个新的const声明语句iota会重新被初始化为0。

举个例子

package main

import "fmt"

//声明常量
const (
   North int = iota
   East
   South
   West
)

func main(){
   fmt.Printf("North = %d, East = %d ,South = %d, West = %d", North, East, South, West)
}

运行结果
North = 0, East = 1 ,South = 2, West = 3

流程控制语句

if-else(分支结构)

常见的书写方式有一下几种

if b > 10 {
   fmt.Println("b大于10")
}
或者
if b > 10 {
   fmt.Println("b大于10")
} else {
   fmt.Println("b小于等于10")
}
或者
if b > 10 {
   fmt.Println("b大于10")
} else if b == 10 {
   fmt.Println("b等于10")
} else {
   fmt.Printf("b小于10")
}

需要注意

关键字if和else之后的左大括号必须和关键字在同一行,如果使用了else-if结构,那么前一段代码的右大括号必须和else if语句在同一行,这个是强制的规则,不满足则编译不通过

for循环

与大多数语言不同的是,Go中的循环语句只支持for关键字,不支持while和do-while结构。关键字for的基本用法与C语言和C++语言非常接近:

product := 1

for i :=1; i < 5; i++ {

   product *= 1

}

可以看到很大的不同就是for后面的表达式不需要使用括号括起来了,Go语言还进一步考虑无线循环的场景,让开发者不需要写for(;;)和do{}-while(),直接间换乘一下写法

i := 0

for {
   i++
   if i > 50 {
      break
   }
}
或者可以简化为
var i int
for i <= 50 {
    i++
}

在使用循环语句时,需要注意一下几点

左大括号必须与for处于同一行

Go语言中for循环和c一样,都允许在循环条件中定义和初始化变量。唯一的区别是,Go语言不支持以逗号为检核的多赋值语句,必须使用平行赋值的方式来初始化多个变量

Go语言的for循环同样支持continue和break来控制循环,但是他提供了更高级的break——可以选择中断哪一个循环,如下例:

JumpLoop:
   for i := 0; i < 10; i++ {
      for j := 0; j < 10; j++ {
         if j == 5 {
            break JumpLoop
         }
         fmt.Println(j)
      }
   }

for-range循环

for-range循环结构是Go语言的一种迭代结构,其应用十分的广泛。for-range可以遍历数组、切片、字符串、map及通道(channel)。 一般形式如下:

for key, val := range 复合变量值 {

​ //…逻辑语句

}

需要注意的是,val始终为集合中对应索引值的复制值。所以对他所做的修改都不会影响集合原有的值。

通过for-range遍历的返回值有一定的规律:

数组、切片、字符串返回索引和值

map返回键和值

通道只返回通道内的值

package main

import "fmt"

func main() {
   //遍历数组、切片
   //key,value代表切片的下标和下标所对应的值
   fmt.Printf("遍历数组、切片\n")
   for key, value := range []int{0, 1, -1, -2} {
      fmt.Printf("key:%d value:%d\n", key, value)
   }

   //遍历字符串
   //key,value分别代表字符串的索引和索引对应的字符
   fmt.Printf("\n遍历字符串\n")
   var str = "hi 加油"
   for key, value := range str {
      fmt.Printf("key:%d value:0x%x\n", key, value)
   }
   //变量中的value的实际值为rune类型,以16进制打印字符的编码

   //遍历map
   //key,value分别代表map的索引建和索引键对应的值
   //在对map遍历时输出的键值是无序的,如果需要有序则需要对结果排序
   fmt.Printf("\n遍历map\n")
   m := map[string]int{
      "go":   100,
      "java": 100,
   }
   for key, value := range m {
      fmt.Println(key, value)
   }

   //遍历channel
   //在遍历通道时只输出一个值,即通道所对应类型的值数据
   fmt.Printf("\n遍历channel\n")
   c := make(chan int)
   go func() {
      c <- 7
      c <- 8
      c <- 9
      close(c)
   }()
   for v := range c {
      fmt.Println(v)
   }
}


运行结果:
遍历数组、切片
key:0 value:0
key:1 value:1
key:2 value:-1
key:3 value:-2

遍历字符串
key:0 value:0x68
key:1 value:0x69
key:2 value:0x20
key:3 value:0x52a0
key:6 value:0x6cb9

遍历map
go 100
java 100

遍历channel
7
8
9

在使用for-range循环遍历某个对象的时候,往往不会同时使用到key和value的值,而是使用其中的一个值,这个时候可以采用一些技巧让代码变得更简单。

比如将前面的map遍历修改一下:

fmt.Printf("\n遍历map\n")
m := map[string]int{
   "go":   100,
   "java": 100,
}
for _, value := range m {
   fmt.Println(value)
}

运行结果:
遍历map
100
100

上面的修改我们将key修改为(_),这个下划线就是匿名变量,可以理解为占位符。匿名变量本身不参加空间分配,也不会占用一个变量名称。

switch-case语句

Go语言中的switch-case语句要比C语言的switch-case语句更加通用,表达式的值不必为常量,甚至不必为整数。

Go语言改进了传统的switch-case语句的语法设计,case与case之间是独立的代码块,不需要通过break语句去避免执行到下一行。

var a = "love"
switch a {
case "love":
   fmt.Println("love")
case "programming":
   fmt.Println("programming")
default:
   fmt.Println("none")
}

运行结果:
love

当然,Go语言还支持一些新的写法

一个分支多个值

分支表达式

eg:

1、
var a = "love"
switch a {
case "love","like":
   fmt.Println("love")
case "programming":
   fmt.Println("programming")
default:
   fmt.Println("none")
}

2、
var r int = 6
	switch {
	case r > 1 && r < 10:
		fmt.Println(r)
	}

goto

在Go语言中,可以通过goto语句跳转到标签,进行代码之间的无条件跳转。另外,goto语句在快速跳出循环、避免重复退出方面也有一定的帮助。使用goto语句能够简化一些代码的实现过程。

在满足条件的时候,如果需要连续退出两层代码,则需要传统编码方式:

	a := []int{0, 1, -1, -2, -3};
	var flag = false
	for key,value :=range a {
		for key1,value2 := range a {
			if key == 2 {
				fmt.Printf("%d %d",key,value)
			}
			if key1 == 3 {
				flag = true
				break
			}
			fmt.Printf("%d %d",key1,value2)
		}
		if flag {
			break
		}
	}

将上面的代码使用Go语言的goto进行优化:

	a := []int{0, 1, -1, -2, -3};
	for key,value := range a {
		for key1,value2 := range a {
			if key == 2 {
				fmt.Printf("第一处打印:%d %d\n",key,value)
			}
			if key1 == 3 {
				goto breakTag
			}
			fmt.Printf("第二处打印%d %d",key1,value2)
		}

		breakTag:
			fmt.Printf("\n")
	}

在上述的代码中,我们使用goto语句“goto breakTag”来跳转到指明的标签处。breakTag是自定义的标签。上述代码中的标签只能被goto使用,不影响代码块的执行流程。在定义breakTag标签之前有一个return语句,此处如果手动返回,则在不满足条件的时候也会执行breakTag代码。

在日常开发中,经常会遇到“多错误处理”的问题,在多错误处理往往存在很多重复的问题:

	err := getUserInfo()
	if err != nil {
		fmt.Printf(err)
		exitProeccess()
		return
	}
	
	err = getEmail()
	if err != nil{
		fmt.Printf(err)
		exitProeccess()
		return
	}
	
	//......

	fmt.Printf("over")

在上述的代码中我们有很多重复的代码。如果后期我们继续增加条件,则需要重复的去去编写雷同代码进行重复修改,极容易出现疏忽或遗漏。这个时候我们可以使用goto语句进行处理:

	err := getUserInfo()
	if err != nil {
		goto breakTag

	}

	err = getEmail()
	if err != nil{
		goto breakTag
	}

	breakTag:
		fmt.Printf(err)
		exitProeccess()
		fmt.Printf("over")
		return

break

Go语言中break语句可以结束for、switch和select的代码块。另外还可以在break语句后面添加标签,表示退出某个便签对应的代码块。田间的标签必须定义在对应的for、switch和select的代码块上。

JumpLoop:
   for i := 0; i < 10; i++ {
      for j := 0; j < 10; j++ {
         if j == 5 {
            break JumpLoop
         }
         fmt.Println(j)
      }
   }

continue

在Go语言中,continue语句是用来结束当前循环,并开始下一次的循环迭代过程。它仅限在for循环中使用。在continue语句后面添加标签,表示结束结束标签对应的语句的当前循环,并开始下一次的外层循环。

	for y := 0; y < 2; y++ {
			outerLoop:
				for x := 0;x < 2 ; x++  {
					for i := 0; i < 3 ;i++  {
						for j := 0 ; j < 5 ;j++  {
							switch j {
							case 3:
								fmt.Println(y,x,i,j)
								continue outerLoop
							}
						}
					}
				}
		}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会编程的羽流云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值