博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go笔记-运算符和流程控制
阅读量:6825 次
发布时间:2019-06-26

本文共 4911 字,大约阅读时间需要 16 分钟。

hot3.png

运算符

  • b = b + a 可以写成b += a
  • 除以浮点数0.0会得到+Inf
a := 1.0 - 1.0	fmt.Println("Hello, ", 9.0/a) // Hello,  +Inf
  • 对于整数和浮点数,可以使用一元运算符 ++(递增)和 --(递减),但只能用于后缀。i++ 带有 ++ 和 -- 的只能作为语句,而非表达式,因此 n = i++ 这种写法是无效的,其它像 f(i++) 或者 a[i]=b[i++] 这些可以用于 C、C++ 和 Java 中的写法在 Go 中也是不允许的.

  • 在运算时 溢出 不会产生错误,Go 会简单地将超出位数抛弃。如果你需要范围无限大的整数或者有理数(意味着只被限制于计算机内存),你可以使用标准库中的 big 包,该包提供了类似 big.Int 和 big.Rat 这样的类型。

  • %取模运算符的符号和被取模数的符号总是一致的,因此-5%3和-5%-3结果都是-2.

流程控制

条件语句if-else

i := 4if i < 0 {	fmt.Println("<0")} else if i == 0 {	fmt.Println("=0")} else {	fmt.Println(">0")}
  • 条件语句不需要使用括号将条件包含起来();
  • 无论语句体内有几条语句,花括号{}都是必须存在的;
  • 左花括号{必须与if或者else处于同一行;
  • 在if之后,条件语句之前,可以添加变量初始化语句,使用;间隔;
if i, j := 0, 0; i <= 0 {		fmt.Println(i, j)	}

i, j只在if-else中有效,如果之前有i,j定义,则会覆盖

选择语句switch

i := 7switch i {case 0:	fmt.Println(0)case 1:	fmt.Println(1)case 2:	fallthrough // 向下执行case 3:	fmt.Println(3)case 4, 5, 6:	fmt.Println("4,5,6")default:	fmt.Println("default")}
  • 左花括号{必须与switch处于同一行;

  • 条件表达式不限制为常量或者整数;

str := "a"	switch str {	case "a":		fmt.Println("a")	case "b":		fmt.Println("b")	}
  • 单个case中,可以出现多个结果选项;

    case 4,5,6

  • 与C语言等规则相反,Go语言不需要用break来明确退出一个case;默认退出

  • 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case,fallthrough不再判断条件

  • 可以不设定switch之后的条件表达式,在此种情况下,整个switch结构与多个if...else...的逻辑作用等同。

i := 0	switch {	case 0 <= i && i <= 3:		fmt.Println("0~3")	case i > 3:		fmt.Println(">3")	}
  • 带初始化语句

    switch i, j := 9, 10; {case i == 1 && j == 10:	fmt.Println("no")case i == 9 && j == 10:	fmt.Println("yes")}
  • fallthrough示例

i := 0switch i {case 0:	fmt.Print("0 ")	fallthroughcase 1:	fmt.Print("1")}
输出:0 1

switch 与类型判断:(database.sql/convert.go:convertAssign())

var src interface{}src = "123"switch s := src.(type) {case string:	fmt.Printf("1:type:%T, value:%v\n", s, s)	fmt.Println(strconv.ParseInt(s, 10, 64))default:	fmt.Printf("2:type:%T, value:%v", s, s)}

循环语句for

  • 只支持for,不支持while,do-while
  • 左花括号{必须与for处于同一行。
  • 特别注意,永远不要在循环体内修改计数器,这在任何语言中都是非常差的实践!
  • Go语言中的for循环与C语言一样,都允许在循环条件中定义和初始化变量,唯一的区别是,Go语言不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量
for i, n := 0, 10; i < n; i++ {		fmt.Printf("%d\t", i)	}
  • 支持continue和break来控制循环
for i, n := 0, 10; ; i++ {		fmt.Printf("%d\t", i)		if i >= n {			break		}	}loop:	for i := 0; ; i++ {		fmt.Printf("for1 :%d ", i)		for j := 0; j <= i; j++ {			if i == 1 && j == 1 {				break loop			}		}	}
  • 无限循环
for {}
  • 只有判断条件,相当于while
for i < 10 {}
  • 循环变量Unicode字符
for i, v := range "汉字\x80" {		fmt.Printf("character %#U starts at byte position %d\n", v, i)	}

输出:

character U+6C49 '汉' starts at byte position 0character U+5B57 '字' starts at byte position 3character U+FFFD '�' starts at byte position 6

错误的编码(上例中的\x80)会占用一个字节,使用U+FFFD来代替

注意变量i第二次是3,而不是1

当for i:=range “sss”时,i代表的是下标。

  • Go没有逗号操作符,并且++和--是语句而不是表达式。因此,如果你想在for中运行多个变量,你需要使用并行赋值(尽管这样会阻碍使用++和--)
for i, j := 0, 5; i < j; i, j = i+1, j-1 {	fmt.Println(i, j)}
  • 循环遍历修改数组

当使用下面的方式修改数组时: items := [...]int{10, 20, 30, 40, 50} for _, item := range items { item *= 2 } fmt.Println(items)

items的元素没有被修改。因为item是元素的拷贝而不是指针。 使用下面的方式可修改: items := [...]int{10, 20, 30, 40, 50} for i, _ := range items { items[i] *= 2 }

- for中变量的作用域 for i := 0; i < 3; i++ { for i := 0; i < 3; i++ { fmt.Println(i) } }

内层for也声明了i,这说明这个i屏蔽了外层的i,所以最后输出的是9个数。

for range

var x = []int{5, 12, 32}	// 使用值和索引	for i, v := range x {		fmt.Println(i, "=>", v)	}		// 只使用索引	for v := range x {		fmt.Println(v) // v是索引,0-3	}		// 只使用值	for _, v := range x {		fmt.Println(v)	}		// 不使用循环中的值	for _ = range x {		fmt.Println(80)	}		// 不使用循环中的值,需要1.4以后版本	for range x {		fmt.Println(90)	}

range会复制对象

a := [3]int{0, 1, 2}// Q: range时内存中是不是有一个原数组和一个拷贝的数组for i, v := range a {	if i == 0 {		a[1], a[2] = 999, 999 // 修改原数组		fmt.Printf("%v, %p \n", a, &a)	}	a[i] = v + 100 // 此时v是range之前原数组复制的值	fmt.Printf("%v, %p \n", a, &a)}fmt.Printf("%v, %p \n", a, &a)

输出:

[0 999 999], 0x20819e020 [100 999 999], 0x20819e020 [100 101 999], 0x20819e020 [100 101 102], 0x20819e020 [100 101 102], 0x20819e020

i和v的值在range时就被拷贝了,而引用类型不会复制底层数据:

s := []int{1, 2, 3, 4, 5}for i, v := range s { // 复制 struct slice {pointer, len, cap}	if i == 0 {		s = s[:3]  // 对slice的修改不会影响range,修改的是range外的s		s[2] = 100 // 对底层数据的修改,这里的s也是range外的	}	fmt.Println(i, v)}fmt.Println(s)

输出:

0 11 22 1003 44 5[1 2 100]

另外两种引用类型 map, channel 是指针包装,而不像 slice 是 struct。

for和闭包

arr := []int{12, 34, 56}	for _, v := range arr {		go func() {			fmt.Println(v)		}()	}	time.Sleep(5 * time.Second)

上面输出都是56.原因不明。

使用下面的语句可以达到遍历的目的:

arr := []int{12, 34, 56}	for _, v := range arr {		go func(v int) {			fmt.Println(v)		}(v)	}	time.Sleep(5 * time.Second)

goto语句

func myfunc() {	i := 0HERE:	fmt.Println(i)	i++	if i < 10 {		goto HERE	}}

如果您必须使用 goto,应当只使用正序的标签(标签位于 goto 语句之后),但注意标签和 goto 语句之间不能出现定义新变量的语句,否则会导致编译失败。

// compile error goto2.go:8: goto TARGET jumps over declaration of b at goto2.go:8package mainimport "fmt"func main() {		a := 1		goto TARGET // compile error		b := 9	TARGET:  		b += a		fmt.Printf("a is %v *** b is %v", a, b)}

break和continue

break可用于 for, switch, select, 而 continue 只能用于 for.

转载于:https://my.oschina.net/u/2004526/blog/847107

你可能感兴趣的文章