Go02-运算符+流程控制

发布时间 2023-03-26 13:17:33作者: 行稳致远方

Go02-运算符+流程控制

1.运算符基本介绍

  1. Go中的运算符分为:算术运算符、赋值运算符、比较运算符/关系运算符、逻辑运算符、位运算符和其他运算符。
  2. Go中没有三元运算符?。

2.算术运算符

// 1 算术运算符。
// + 正号;- 负号;
// + 加;- 减;* 乘;/ 除;% 取余;
// ++ 自增;-- 自减。
// + 字符串相加。

// 2 /的特点。如果/运算的都是整数,则结果会去掉小数,返回整数。
fmt.Println(10 / 4) // 2
var a1 float64 = 10 / 4
fmt.Println(a1) // 2

// 如果运算想要得到小数,就需要转换为小数后再进行运算。
var a2 float64 = 10.0 / 4
fmt.Println(a2) // 2.5

var a3 float64 = float64(10) / 4
fmt.Println(a3) // 2.5

// 3 %取模运算。a % b = a - a / b * b
fmt.Println(10 % 3) // 1
fmt.Println(-10 % 3) // -1 -10-(-10/3*3)=-10--9=-10+9=-1
fmt.Println(10 % -3) // 1
fmt.Println(-10 % -3) // -1

// 4 ++和--。
// 4.1 ++和--只能独立使用。
var b1 = 10
b1++
fmt.Println(b1) // 11
// ++和--只能单独使用,否则编程错误。syntax error: unexpected ++ at end of statement
// var b2 = b1++

// 4.2 ++和--只能进行后++或者后--。Go中去掉了java/c中自增和自减容易混淆的写法,让Go更加的简洁。
var c1 = 10
c1++
// 不能前++和前--。否则报错:syntax error: unexpected ++, expecting }
// ++c1
// --c1

3.关系运算符

// 1 关系运算符包含:== 相等于;!= 不等于;< 小于;> 大于;
// <= 小于等于;>= 大于等于。
a := 10
b := 20
fmt.Println(a == b) // false
fmt.Println(a != b) // true
fmt.Println(a < b) // true
fmt.Println(a > b) // false
fmt.Println(a <= b) // true
fmt.Println(a >= b) // false

// 2 关系运算符的结果是bool型,要么值为true,要么值为false。
// 3 由关系运算符组成的表达式成为关系表达式,关系表达式常用在if结构和循环结构中。

4.逻辑运算符

func main() {
	// 1 逻辑运算符包含:&& 逻辑与运算;|| 逻辑或运算;
	// ! 逻辑非运算。
	// && 逻辑与运算,两边都为真,才为真。
	fmt.Println(true && true) // true
	// || 逻辑或运算,两边都为假,才为假。
	fmt.Println(false || false) // false
	// ! 逻辑非运算,取反运算。
	fmt.Println(!true) // false

	// 2 &&也称为短路与,第一个条件为false时,则第二个条件不执行,直接返回false。
	a1 := 10
	if a1 < 0 && test() {
		fmt.Println("&&")
	}

	// 3 ||也称为短路或,第一个条件为true时,则第二个条件不执行,直接返回true。
	// ||
	if a1 < 20 || test() {
		fmt.Println("||")
	}
}

func test() bool {
	fmt.Println("test执行了")
	return true
}

5.赋值运算符

// 1 赋值运算符包含:= 等于;+= 加等;-= 减等;*= 乘等;
// /= 除等;%= 余等;
// <<= 左移后赋值;>>= 右移后赋值;&= 按位与后赋值;
// ^= 按位异或后赋值;|= 按位或后赋值。

// 2 不使用中间变量交换两个变量。
a := 10
b := 20
a = a + b
b = a - b
a = a - b
fmt.Println(a, b)

6.位运算符和其他运算符

// 1 位运算包含:& 按位与运算,同为1,结果为1,否则为0;
// | 按位或运算,有一个为1,则结果为1,否则为0。
// ^ 按位异或运算,不同为1,相同为0;
// << 左移运算,<< n,左移n位,相当与乘以2的n次方;
// >> 右移运算,>> n,右移n位,相当与除以2的n次方;
fmt.Println(2 << 2) // 8
fmt.Println(16 >> 1) // 8

// 2 其他运算符。
// & 取地址运算符,返回变量的地址。
// *,指针变量,返回指针指向的地址的保存的数据。
a := 10
b := &a
fmt.Println(&b, *b) // 0xc000006030 10

// 3 Go不支持三元运算。

7.获取用户输入

  1. 获取用户的输入方式一,fmt.Scanln()。
var name string
var age int
var store float64
var isPass bool

fmt.Println("请输入姓名")
// fmt.Scanln()获取一行的数据,输入回车后输入结束。
fmt.Scanln(&name)

fmt.Println("请输入年龄")
fmt.Scanln(&age)

fmt.Println("请输入分数")
fmt.Scanln(&store)

fmt.Println("请输入是否通过考试")
fmt.Scanln(&isPass)

fmt.Println(name, age, store, isPass)
  1. 获取用户输入的方式二,fmt.Scanf()。
var name string
var age int
var store float64
var isPass bool

fmt.Println("请依次输入姓名 年龄 成绩 是否通过考试,并使用空格隔开。")
// fmt.Scanf()可以指定输入的格式,输入回车,输入结束。
fmt.Scanf("%s %d %f %v", &name, &age, &store, &isPass)
fmt.Println(name, age, store, isPass)

8.进制运算和表示

// 1 Go中不能使用二进制来表示一个整数,但是可以输出二进制。
var a1 int = 5
fmt.Printf("%b\n", a1) // 101

// 2 定义一个八进制数,使用数字0开头来表示一个八进制数。
var a2 int = 011
fmt.Println(a2) // 9

// 3 定义一个十六进制数,使用0x或者0X开头来表示一个十六进制数。
var a3 int = 0x11
var a4 int = 0X11
fmt.Println(a3, a4) // 17 17

// 4 原码 反码 补码
// 4.1 对于有符号的数,二进制的最高位是符号位,0表示正数,1表示负数。
// 4.2 正数的原码、反码和补码都是一样的。
// 4.3 负数的反码等于其符号位不变,其它位取反。
// 4.4 负数的补码=负数的反码+1。
// 4.5 0的反码和补码都是0。
// 4.6 计算机在运算的时候都是以补码进行运算的。

// 2的补码 0000 0010
// 3的补码 0000 0011

// 0000 0010 & 0000 0011 = 0000 0010 = 2
fmt.Println(2 & 3) // 2

// 0000 0010 & 0000 0011 = 0000 0011 = 3
fmt.Println(2 | 3) // 3

// 0000 0010 & 0000 0011 = 0000 0001 = 1
fmt.Println(2 ^ 3) // 1

// -2的原码 1000 0010;-2的反码 1111 1101;-2的补码 1111 1110
// 1111 1110 & 0000 0011 = 0000 0010 = 2
fmt.Println(-2 & 3) // 2

// 5 >>左移和<<右移。
// 左移,符号位不变,地位补零。
// 右移,符号位不变,使用符号位补溢出的高位。

9.单分支结构-if

// 1 if单分支基本语法。
a1 := 10
// a1 > 0
if a1 > 0 {
    fmt.Println("a1 > 0")
}

// 2 单分支可以定义变量,但是定义的变量只能在当前分支的代码块中使用。
// a2 > 10
if a2 := 20; a2 > 10 {
    fmt.Println("a2 > 10")
}

// 3 if代码块中只有一行代码,也需要写大括号,否则会报错。
// 报错:missing { after if clause
/*
if a3 := 30; a3 > 10
	fmt.Println("a3 > 10")
*/

10.双分支结构-if...else

// 1 双分支结构if...else
a1 := 10
// a1 > 0
if a1 > 0 {
    fmt.Println("a1 > 0")
} else {
    fmt.Println("a1 不大于 0")
}

// 2 if...else中,else不能换行。
// a2 := 20
// 报错:unexpected else, expecting }
/*
	if a2 > 10 {
		fmt.Println("a2 > 10")
	}
	else {
		fmt.Println("a2 不大于 10")
	}
	*/

// 3 if中的条件可以写为在()中,但是不推荐写()。
a3 := 30
// 不推荐将条件写在()中。
// a3 > 0
if (a3 > 0) {
    fmt.Println("a3 > 0")
}

11.多分支结构体-if...else if...else

// 1 多分支结构。
a1 := 10
// a1 > 1
if a1 > 30 {
    fmt.Println("a1 > 30")
} else if a1 > 20 {
    fmt.Println("a1 > 20")
} else if a1 > 1 {
    fmt.Println("a1 > 1")
} else {
    fmt.Println("else")
}

// 2 Go中if判断必须是条件表达式,不能是赋值语句。
// a2 := false
// 报错。a2 = true used as value
/*
	if a2 = true {
		fmt.Println("a1 = true")
	}
	*/

// 3 计算一个数的平方根。
var a3 float64 = 16
fmt.Println(math.Sqrt(a3)) // 4

12.switch结构

func main() {
	// 1 Go中的switch不需要break;Go中case表达式可以有多个,使用逗号隔开。
	a1 := 10
	// 10
	switch a1 {
		case 1, 2:
			fmt.Println("1, 2")
		case 10:
			fmt.Println("10")
		default:
			fmt.Println("default")
	}

	// 2 switch后跟表达式、变量、常量、有返回值的函数都可以。
	// 2.1 switch后跟常量。
	// 10
	switch 10 {
		case 1, 2:
			fmt.Println("1,2")
		case 10:
			fmt.Println("10")
	}

	// 2.2 switch后跟又返回值的函数。
	a2 := 10
	// 11
	switch test01(a2) {
		case 10:
			fmt.Println("10")
		case 11:
			fmt.Println("11")
	}

	// 3 case后面的表达式如果是常量值,则要求不能重复。
	// a3 := 10
	// case后的常量值重复。报错:duplicate case 1 in switch
	/*
	switch a3 {
		case 1, 2:
			fmt.Println("1,2")
		case 1:
			fmt.Println("1")
	}
	*/

	// 4 switch可以不带表达式,类似if...else,case中可以写布尔表达式。
	a4 := 10
	// a4 > 1
	switch {
		case a4 > 20:
			fmt.Println("a4 > 20")
		case a4 > 10:
			fmt.Println("a4 > 10")
		case a4 > 1:
			fmt.Println("a4 > 1")
	}

	// 4 switch后可以定义一个变量,使用分号结束,但是不推荐。
	// a5 > 1
	switch a5 := 10; {
		case a5 > 20:
			fmt.Println("a5 > 20")
		case a5 > 10:
			fmt.Println("a5 > 10")
		case a5 > 1:
			fmt.Println("a5 > 1")
	}

	// 5 switch的fallthrough可以穿透case语句块,默认穿透一层。
	a6 := 10
	// 10 20
	switch a6 {
	case 1:
		fmt.Println("1")
	case 10:
		fmt.Println("10")
		fallthrough // fallthrough会穿透case,默认穿透一层。
	case 20:
		fmt.Println("20")
	case 30:
		fmt.Println("30")
	}

	// 6 switch可以用来判断interface变量实际的类型。
	var a7 interface{}
	a8 := 12.12
	a7 = a8
	// float64
	switch a7.(type) {
		case float32:
			fmt.Println("float32")
		case float64:
			fmt.Println("float64")
	}

	// 7 switch和if的使用场景。
	// 7.1 如果判断的是具体的数值,并且数值类型为整形、浮点型、字符和字符串则可以使用switch。
	// 7.2 对于区间判断和结果为bool类型的判断,使用if较多。
}

func test01(a int) int {
	return a + 1
}

13.循环结构-for

  1. for循环的三种写法。
// 1 for循环第一种写法。
// 0 1
for i := 0;i < 2;i++ {
    fmt.Println(i)
}

// 2 for循环第二种写法。
// 0 1
a1 := 0
for a1 < 2 {
    fmt.Println(a1)
    a1++
}

// 3 for循环的第三种写法,这种写法是一个死循环,需要结合break使用。
a2 := 0
// 0 1
for {
    fmt.Println(a2)
    a2++
    if a2 == 2 {
        break
    }
}
  1. for...range。
// 4.1 传统的方式遍历字符串。
a3 := "abc"
// a	b	c
for i := 0; i < len(a3); i++ {
    fmt.Printf("%c\t", a3[i])
}

fmt.Println()
// 4.2 for-range遍历字符串。
a4 := "abc"
// 0-a	1-b	2-c
for index, value := range a4 {
    fmt.Printf("%d-%c\t", index, value)
}
  1. 遍历字符串时的乱码问题。
// 1 使用传统的方式遍历有中文的字符串时,就会出现乱码问题。
// 因为一个汉字占用三个字节,所以在遍历汉字时会出现乱码问题。
a5 := "a张"
// a	å	¼
for i := 0;i < len(a5);i++ {
    fmt.Printf("%c\t", a5[i])
}

fmt.Println()
// 2 将字符串转换为rune类型的切片解决传统字符串遍历的乱码问题。
a6 := "a张"
a7 := []rune(a6)
// a	张
for i := 0; i < len(a7); i++ {
    fmt.Printf("%c\t", a7[i])
}

fmt.Println()
// 3 使用for-range遍历有中文的字符串是没有乱码问题的。
// for-range按照字符的方式遍历字符串,所以没有乱码的问题。
a8 := "a张"
// 0-a	1-张
for index, value := range a8 {
    fmt.Printf("%d-%c\t", index, value)
}
  1. Go中没有while和do...while,但是可以使用for循环来完成while和do...while的效果。

14.跳转控制语句-break

// 1 break终止语句块的执行,如终止当前for循环或者跳出switch语句。
// 2 生成随机数,当生成的随机数为99时退出for循环。需要多少次,才能生成99这个随机数。
count := 0

// 返回1970年1月1日 0时0分0秒到当前时间的毫秒数。
time.Now().Unix()
time.Now().UnixNano() // 返回1970年1月1日 0时0分0秒到当前时间的纳秒数。
for  {
    // 给rand设置一个随机的种子,生成的数据才是随机的。
    rand.Seed(time.Now().UnixNano())
    n := rand.Intn(100) + 1
    count++
    if n == 99 {
        break
    }
}
// for循环了8633次,生成了随机数99
fmt.Printf("for循环了%d次,生成了随机数99\n", count)

// 3 break出现在多层嵌套语句时,通过标签指明终止的语句块。
a1 := 1
// 1
label1:
for {
    fmt.Println(a1)
    for {
        if a1 == 1 {
            break label1
        }
    }
}

15.跳转控制语句-continue

// 1 continue用于结束当前循环,继续执行下次循环。
a1 := 0
/*
	a1 0
	a2 1
	a1 1
	a2 1
	 */
for a1 < 2 {
    fmt.Println("a1", a1)
    a1++
    for a2 := 0; a2 < 2; a2++ {
        if a2 == 0 {
            continue
        }
        fmt.Println("a2", a2)
    }
}

// 2 continue出现在多层嵌套语句时,通过标签指明跳转到的语句块。
b1 := 0
// b1 0
// b1 1
label1:
for b1 < 2 {
    fmt.Println("b1", b1)
    b1++
    for b2 := 0; b2 < 2; b2++ {
        if b2 == 0 {
            continue label1
        }
        fmt.Println("b2", b2)
    }
}

16.跳转控制语句-goto

// 1 goto可以无条件的跳转到程序指定的行。
// 2 goto一般结合条件语句if一起使用。
// 3 Go中一般不主张使用goto,以免造成程序流程混乱,给代码阅读和调试带来困难。
a1 := 10
if a1 > 1 {
    goto label1
}

// 是输出3 4
fmt.Println("1")
fmt.Println("2")
label1:
fmt.Println("3")
fmt.Println("4")

17.跳转控制语句-return

func main() {
	// 1 return使用在方法或者函数中,用来跳出所在的方法和函数。
	// a 1
	test01(1)
}

func test01(a int) {
	fmt.Println("a", a)
	if a == 1 {
		return
	}
	fmt.Println("a不等于1")
}