Go的研习笔记-day4(以Java的视角学习Go)

控制结构

在Java程序中我们使用的逻辑结构有if-else,switch,while,for,do…while
在go语言中多加了select结构去掉了wihle和do…while
go语言的条件结构和分支结构

  • if-else 结构
  • switch 结构
  • select 结构,用于 channel 的选择
  • for (range) 结构
    Go 完全省略了 if、switch 和 for 结构中条件语句两侧的括号。如果需要中断的话依然可以使用break,continue,return,和goto来调整程序结构。

if-else 结构

Java中的实现
if( 1==1 ) {
//do something
}else if  2!=3  {
	// do something else	
} else{
//do otherthing
}
go语言中的实现则不需要括号
if 1==1  {
//do something
}else if 2!=3 {
	// do something else	
} else{
//do otherthing
}

关键字 if 和 else 之后的左大括号 { 必须和关键字在同一行,如果你使用了 else-if 结构,则前段代码块的右大括号 } 必须和 else-if 关键字在同一行。这两条规则都是被编译器强制规定的。
注意一种现象,Java中是Ok的但是在go语言会认为是非法的,比如如下的这种

if x{
}
else {	// 无效的
}

要注意的是,在你使用 gofmt 格式化代码之后,每个分支内的代码都会缩进 4 个或 8 个空格,或者是 1 个 tab,并且右大括号与对应的 if 关键字垂直对齐。
在有些情况下,条件语句两侧的括号是可以被省略的;当条件比较复杂时,则可以使用括号让代码更易读。条件允许是符合条件,需使用 &&、|| 或 !,你可以使用括号来提升某个表达式的运算优先级,并提高代码的可读性。
Go 1.1版本以前,使用if-else的话不能两个条件内都同时使用return语句,在1.1版本以后已经修复。
实际中常用的例子

  • 判断一个字符串是否为空
    if str == “” { … }
    if len(str) == 0 {…}
  • 判断运行 Go 程序的操作系统类型,这可以通过常量 runtime.GOOS 来判断
    if runtime.GOOS == “windows” {
    . …
    } else { // Unix-like
    . …
    }

测试多返回值函数的错误
比如如下的例子:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var orig string = "ABC"
	// var an int
	var newS string
	// var err error

	fmt.Printf("The size of ints is: %d\n", strconv.IntSize)	  
	// anInt, err = strconv.Atoi(origStr)
	an, err := strconv.Atoi(orig)
	if err != nil {
		fmt.Printf("orig %s is not an integer - exiting with error\n", orig)
		return
	} 
	fmt.Printf("The integer is %d\n", an)
	an = an + 5
	newS = strconv.Itoa(an)
	fmt.Printf("The new string is: %s\n", newS)
}

测试 err 变量是否包含一个真正的错误(if err != nil)的习惯用法。如果确实存在错误,则会打印相应的错误信息然后通过 return 提前结束函数的执行。我们还可以使用携带返回值的 return 形式,例如 return err。这样一来,函数的调用者就可以检查函数执行过程中是否存在错误了。
如果我们想要在错误发生的同时终止程序的运行,我们可以使用 os 包的 Exit 函数:
if err != nil {
fmt.Printf(“Program stopping with error %v”, err)
os.Exit(1)
}

switch结构
我们可以回想下Java中的话switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量.
但是go语言这里就强大了,任意的表达式在这里都可以。
比如如下这种格式:

package main

import "fmt"

func main() {
	var num1 int = 7

	switch {
	    case num1 < 0:
		    fmt.Println("Number is negative")
	    case num1 > 0 && num1 < 10:
		    fmt.Println("Number is between 0 and 10")
	    default:
		    fmt.Println("Number is 10 or greater")
	}
}
还可以特殊的一种方式表达
switch result := calculate() {
	case result < 0:
		...
	case result > 0:
		...
	default:
		// 0
}
当然还可以这么玩,变量 a 和 b 被平行初始化,然后作为判断条件:
switch a, b := x[i], y[j] {
	case a < b: t = -1
	case a == b: t = 0
	case a > b: t = 1
}

fallthrough关键字作用

package main

import (
	"fmt"
)

func main() {
		k := 6
	switch k {
	case 4:
		fmt.Println("was <= 4")
		fallthrough
	case 5:
		fmt.Println("was <= 5")
		fallthrough
	case 6:
		fmt.Println("was <= 6")
		fallthrough
	case 7:
		fmt.Println("was <= 7")
		fallthrough
	case 8:
		fmt.Println("was <= 8")
		fallthrough
	default:
		fmt.Println("default case")
	}
}

这里是引用

for结构
go语言的for循环结构比较强大
注意事项 其它许多语言中也没有发现和 do while 完全对等的 for 结构,可能是因为这种需求并不是那么强烈

  • 基于计数器的迭代
    假设我们现在Java中实现一个for循环可以如下方式实现
for( int i = 0; i < 5; i ++){
System.out.println("This is the "+i+" iteration");
}
用go语言实现则为如下方式扩号不需要其余一样
格式:for 初始化语句; 条件语句; 修饰语句 {}
package main

import "fmt"

func main() {
	for i := 0; i < 5; i++ {
		fmt.Printf("This is the %d iteration\n", i)
	}
}
假设你用Java规范写到了go语言中,这个代码块则为无效语句。
如果现在想要定义多个计数器,可以通过这样的方式实现。
for i, j := 0, N; i < j; i, j = i+1, j-1 {}
  • 基于条件判断的迭代
    类似Java中的while循环如何实现呢?
    go语言中可以如下格式实现:
package main

import "fmt"

func main() {
	var i int = 5

	for i >= 0 {
		i = i - 1
		fmt.Printf("The variable i is now: %d\n", i)
	}
}
  • 无限循环
    for true {},但是为了简洁我们通常写为 for {}
    应用场景:阻塞的服务器
for t, err = p.Token(); err == nil; t, err = p.Token() {
	...
}
  • for-range结构
    对于数组和map经常会使用该结构,如果想要参考类比的话可以参考Java中的foreach语句
    格式:for ix, val := range coll { }。
    要注意的是,val 始终为集合中对应索引的值拷贝,因此它一般只具有只读性质,对它所做的任何修改都不会影响到集合中原有的值(如果 val 为指针,则会产生指针的拷贝,依旧可以修改集合中的原值)。一个字符串是 Unicode 编码的字符(或称之为 rune)集合,因此您也可以用它迭代字符串:
    每个 rune 字符和索引在 for-range 循环中是一一对应的。它能够自动根据 UTF-8 规则识别 Unicode 编码的字符。
for pos, char := range str {
...
}
  • break与continue
    与Java用法道理相通
  • 标签与goto
    for、switch 或 select 语句都可以配合标签(label)形式的标识符使用,即某一行第一个以冒号(:)结尾的单词(gofmt 会将后续代码自动移至下一行)
    (标签的名称是大小写敏感的,为了提升可读性,一般建议使用全部大写字母)
package main

import "fmt"

func main() {

LABEL1:
	for i := 0; i <= 5; i++ {
		for j := 0; j <= 5; j++ {
			if j == 4 {
				continue LABEL1
			}
			fmt.Printf("i is: %d, and j is: %d\n", i, j)
		}
	}

}
本例中,continue 语句指向 LABEL1,当执行到该语句的时候,就会跳转到 LABEL1 标签的位置。
您可以看到当 j==4 和 j==5 的时候,没有任何输出:标签的作用对象为外部循环,因此 i 会直接变成下一个循环的值,而此时 j 的值就被重设为 0,即它的初始值。如果将 continue 改为 break,则不会只退出内层循环,而是直接退出外层循环了。另外,还可以使用 goto 语句和标签配合使用来模拟循环。

特别注意 使用标签和 goto 语句是不被鼓励的:它们会很快导致非常糟糕的程序设计,而且总有更加可读的替代方案来实现相同的需求。

package main

func main() {
	i:=0
	HERE:
		print(i)
		i++
		if i==5 {
			return
		}
		goto HERE
}
发布了213 篇原创文章 · 获赞 258 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/wolf_love666/article/details/98191100
今日推荐