Go语言基础:运算符_流程控制循环_数组_切片

Posted Zeker62

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言基础:运算符_流程控制循环_数组_切片相关的知识,希望对你有一定的参考价值。

借鉴了李文周老师的博客

运算符

算数运算符

+相加
-相减
*相乘
/相除
%求余

关系运算符

==检查两个值是否相等,如果相等返回 True 否则返回 False。
!=检查两个值是否不相等,如果不相等返回 True 否则返回 False。
>检查左边值是否大于右边值,如果是返回 True 否则返回 False。
>=检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。
<检查左边值是否小于右边值,如果是返回 True 否则返回 False。
<=检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。

位运算符

&参与运算的两数各对应的二进位相与。 (两位均为1才为1)
|参与运算的两数各对应的二进位相或。 (两位有一个为1就为1)
^参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 (两位不一样则为1)
<<左移n位就是乘以2的n次方。 “a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。
>>右移n位就是除以2的n次方。 “a>>b”是把a的各二进位全部右移b位。
package main

import "fmt"

// 位运算符
func main() {
   a:=5 //0101
   b:=6 //0110
   //位运算符使用的是二进制运算

   // 0101与0110按位与,得到0100=4
   fmt.Println(a&b)
   // 0101与0110按位或,得到0111=7
   fmt.Println(a|b)
   // 0101与0110按位异或,得到0011=3
   fmt.Println(a^b)
   // 0101向左偏移6位,得到0101000000=256+64
   fmt.Println(a<<b)
   // 如果偏移量超过了数据类型的范围,则多的位数丢弃,比如
   var c int8=64 
   fmt.Println(c<<b) //64为1000000 偏移6位为 1000000000000超过了8位的范围,所以高位舍弃
   //  0101与0110向右便宜6位,已经将101偏移出范围了,所以为0
   fmt.Println(a>>b)
}

逻辑运算符

&&逻辑 AND 运算符。 如果两边的操作数都是 True,则为 True,否则为 False。
||逻辑 OR 运算符。 如果两边的操作数有一个 True,则为 True,否则为 False。
!逻辑 NOT 运算符。 如果条件为 True,则为 False,否则为 True。

赋值运算符

=简单的赋值运算符,将一个表达式的值赋给一个左值
+=相加后再赋值
-=相减后再赋值
*=相乘后再赋值
/=相除后再赋值
%=求余后再赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
|=按位或后赋值
^=按位异或后赋值

流程控制

if语句

if语句的写法相比较于C语言,条件判断的时候没有括号。相比较于Python语言,在条件执行语句的时候具有花括号括起

func main(){
	//一般写法
	var your_age=18
	if your_age<18{
		fmt.Println("you are too young!")
	}else if 18<=your_age && your_age<35{
		fmt.Println("it is the best")
	}else{
		fmt.Println("you are too old to do this job")
	}
	fmt.Println("your age is",your_age)
}

if条件判断还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断。这种写法会导致此变量的作用域只在条件判断内部,如下所示

func main(){
	//特殊写法
	if your_age:=18;your_age<18{
		fmt.Println("you are too young!")
	}else if 18<=your_age && your_age<35{
		fmt.Println("it is the best")
	}else{
		fmt.Println("you are too old to do this job")
	}
	fmt.Println("your age is",your_age)
}

此时会报错:

# command-line-arguments
.\\if02.go:15:28: undefined: your_age

for循环

Go语言中只有for循环,没有while或者其他循环.

条件表达式返回true时循环体不停地进行循环,直到条件表达式返回false时自动退出循环。

一般形式,此时i的作用域是for循环体

func main(){
	for i:=0 ;i<10;i++{
		fmt.Print(i," ")
	}
}
//0 1 2 3 4 5 6 7 8 9 

for循环的初始语句可以被忽略,但是初始语句后的分号必须要写,例如:

func main() {
	i:=0
	for ;i<10;i++{
		fmt.Print(i)
	}
}

for循环的初始语句和结束语句都可以省略,逐渐向while循环转换,在书写时要防止死循环

func main() {
	i:=0
	for i<10{
		fmt.Print(i)
		i++
	}
}

for range 键值循环

Go语言中可以使用for range遍历数组、切片、字符串、map 及通道(channel)。即可以遍历类似于字典这种数据结构, 通过for range遍历的返回值有以下规律:

  1. 数组、切片、字符串返回索引和值。
  2. map返回键和值。
  3. 通道(channel)只返回通道内的值。

使用range需要有两个变量来接收,如果使用一个变量接收的话,就只接收索引

func main() {
	var l =[3]int{1,2,3}
	for a,b :=range l{
		fmt.Printf("%d:%d\\n",a,b)
	}
}
//0:1
//1:2
//2:3

一个变量进行接收

func main() {
   var l =[3]int{1,2,3}
   for b :=range l{
      fmt.Printf("%d\\n",b)
   }
}
//0
//1
//2

Swith 语句

使用switch语句可方便地对大量的值进行条件判断。

func switchDemo1() {
	finger := 3
	switch finger {
	case 1:
		fmt.Println("大拇指")
	case 2:
		fmt.Println("食指")
	case 3:
		fmt.Println("中指")
	case 4:
		fmt.Println("无名指")
	case 5:
		fmt.Println("小拇指")
	default:
		fmt.Println("无效的输入!")
	}
}

Go语言规定每个switch只能有一个default分支。

一个分支可以有多个值,多个case值中间使用英文逗号分隔。

func testSwitch2() {
	switch n := 7; n { //注意此时n的作用域
	case 1, 3, 5, 7, 9:
		fmt.Println("奇数")
	case 2, 4, 6, 8:
		fmt.Println("偶数")
	default:
		fmt.Println(n)
	}
}

分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量。例如:

func switchDemo4() {
	age := 30
	switch {
	case age < 25:
		fmt.Println("好好学习吧")
	case age > 25 && age < 35:
		fmt.Println("好好工作吧")
	case age > 60:
		fmt.Println("好好享受吧")
	default:
		fmt.Println("活着真好")
	}
}

fallthrough语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的。(不常用)

func switchDemo5() {
	s := "a"
	switch {
	case s == "a":
		fmt.Println("a")
		fallthrough
	case s == "b":
		fmt.Println("b")
	case s == "c":
		fmt.Println("c")
	default:
		fmt.Println("...")
	}
}

goto跳转(不常用)

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

package main

import "fmt"

func gotoDemo2() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// 设置退出标签
				goto breakTag
			}
			fmt.Printf("%v-%v\\n", i, j)
		}
	}
	return
	// 标签
breakTag:
	fmt.Println("结束for循环")
}
func main() {
	gotoDemo2()
}

break和continue

break语句可以结束forswitchselect的代码块。

break语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的forswitchselect的代码块上。 举个例子:

func breakDemo1() {
BREAKDEMO1:
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				break BREAKDEMO1
			}
			fmt.Printf("%v-%v\\n", i, j)
		}
	}
	fmt.Println("...")
}

continue语句可以结束当前循环,开始下一次的循环迭代过程,仅限在for循环内使用。

continue语句后添加标签时,表示开始标签对应的循环。例如:

func continueDemo() {
forloop1:
   for i := 0; i < 5; i++ {
      // forloop2:
      for j := 0; j < 5; j++ {
         if i == 2 && j == 2 {
            continue forloop1
         }
         fmt.Printf("%v-%v\\n", i, j)
      }
   }
}

数组

数组是同一种数据类型元素的集合。 在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化。即当时定义了容量为多大的数组,这个容量就不可再变化

数组定义

Go语言数组的定义和其他语言都不太一致,具体格式为:

var 数组名 [数组大小]数组内成员数据类型

比如

var array [3]int

这就定义了名为array,大小为3,int类型的数组

数组初始化

直接/一般初始化

数组在定义的时候就可以直接初始化:

格式为

var 数组名 = [数组大小]数组内成员数据类型{数组值且用逗号分隔}
数组名 := [数组大小]数组内成员数据类型{数组值且用逗号分隔}

例如

var array= [3]int{1,2,3}
fmt.Print(array)
//[1 2 3]
a := [3]int{10, 20, 30}

部分/默认值初始化

如果不初始化数组或者部分初始化,那么没初始化的成员会具有默认值

func main() {
   // 数组定义
   var array[3]int
   var array_string[3]string
   var array_string_2=[4]string{"上海","北京"}
   var array_bool[3]bool
   var array_int=[3]int{1,2}
   fmt.Println(array)
   fmt.Println(array_string)
   fmt.Println("部分初始化",array_string_2)
   fmt.Println(array_bool)
   fmt.Println("部分初始化:",array_int)
}
//[0 0 0]
//[  ]
//部分初始化 [上海 北京  ]
//[false false false]
//部分初始化: [1 2 0]

不确定初始化

当数组的大小不确定时,可以用[…]进行省略,系统会自动分配合适的空间给数组

package main

import "fmt"

func main() {
   var array[3]int
   var array_string_2=[...]string{"上海","北京"}
   var array_bool[3]bool
   var array_int=[...]int{1,2}
   fmt.Println(array)
   fmt.Println("不确定初始化",array_string_2)
   fmt.Println(array_bool)
   fmt.Println("不确定初始化:",array_int)
}

此外,不确定符号只能用于初始化,不能用于定义,如下的行为就是错误的

var array_string[...]string

索引值初始化

也可以直接通过索引值给数组初始化:

func main() {
   var array=[7]int{1:2,5:100,2:10}
   var array2=[...]int{1:2,20:10}
   fmt.Print(array," ")
   fmt.Printf("type of array2:%T \\n",array)
   fmt.Print(array2," ")
   fmt.Printf("type of array2:%T",array2)
}
//[0 2 10 0 0 100 0] type of array2:[7]int
//[0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10] type of array2:[21]int

数组遍历

数组的遍历无异于要使用循环结构,下面介绍两种循环结构遍历数组

package main

import "fmt"

func main() {
   var array=[...]int{1,2,3,4,5,6,7,8,9,10}
   //len函数可以获取数组长度
   fmt.Println("使用for循环遍历数组array")
   for i:=0;i<len(array);i++{
      fmt.Print(array[i]," ")
   }
   fmt.Println("\\n使用for range循环遍历数组")
   for _,a:=range array{
      fmt.Print(a," ")
   }
}
//使用for循环遍历数组array
//1 2 3 4 5 6 7 8 9 10
//使用for range循环遍历数组
//1 2 3 4 5 6 7 8 9 10 

多维数组

以二维数组为例

二维数组定义和初始化

和其他语言的二维数组定义模板类似:

var array=[3][2]int{{1,2},{3,4},{5,6}}

此外,定义的时候只有第一层可以使用[…],例如

var array2=[...][2]int{{1,2},{3,4},{5,6},{7,8}}
fmt.Println(array2) //[[1 2] [3 4] [5 6] [7 8]]
fmt.Println(len(array2)) //4

这种行为时不可取的

var array2=[...][...]int{{1,2},{3,4},{5,6},{7,8}}
var array3=[4][...]int{{1,2},{3,4},{5,6},{7,8}}

二维数组遍历

两层循环嵌套,这里演示一下for和for range循环嵌套

package main

import "fmt"

func main() {
   var array2=[...][2]int{{1,2},{3,4},{5,6},{7,8}}
   for i:=0;i<len(array2);i++{
      for _,a:=range array2[i]{
         fmt.Print(a,"\\t")
      }
      fmt.Println()
   }
}
//1	2
//3	4
//5	6
//7	8	

值类型和引用类型

  • 数组是值类型,即当数组进行复制的时候,会额外开辟一个内存空间,这两个内存空间互不干扰,一方发生变化不会影响到另一方。
  • 引用类型指的是指针,即浅复制,开辟一个内存空间不存放原来的数值,而是存放该目标的地址,一方发生变化,就会影响到另一方。
package main

import "fmt"

func change(a [3]int)  {
   a[2]=22
   fmt.Println("在函数体内部时",a)
}
func main() {
   var array=[3]int{1,2,3Go基础2

Go基础2

Go基础2

Golang basic_leaming2 语言容器

Golang basic_leaming2 语言容器

Golang basic_leaming3 流程控制