本篇文章主要介绍程序结构相关的知识,具体包括条件语句、循环、函数和指针等内容。编程
给定一个天然数v,若是它在0-100之间则返回v,若大于100则返回100,小于0则返回0,使用Go语言实现的代码以下:ide
package main import "fmt" func ifTest(v int) int{ if v >100 { //if的条件里面不须要括号 return 100 }else if v <0 { return 0 }else { return v } } func main() { var a int = ifTest(5) fmt.Println(a) } //运行结果: 5
注意到没有if的条件里面不须要括号,建立的文件中不能包含下划线。func ifTest(v int) int
中参数v的前面不须要添加var
关键词,后面的int则是该函数的返回结果。函数式编程
如今来使用Go语言来读取某个文件的信息,如test.txt
中的内容,相应的代码以下:函数
package main import ( "fmt" "io/ioutil" ) func readFieTest(){ const filename = "test.txt" contents, errorinfo :=ioutil.ReadFile(filename) //var contents ,errorinfo = ioutil.ReadFile(filename) if errorinfo != nil { fmt.Println(errorinfo) }else{ fmt.Printf("%s\n",contents) } } func main() { readFieTest() }
读取文件须要采用ioutil包中的ReadFile函数,查看源码可知该函数一次能够返回两个值:ui
func ReadFile(filename string) ([]byte, error) { ...... }
if errorinfo != nil
中的nil就是无的意思,此处就是产生了错误,能够参考这篇文章了解更多关于nil的信息:理解Go语言的nil 。其实上面那种方式不是很简介,可使用相似于Java中的三元表达式:.net
package main import ( "fmt" "io/ioutil" ) func readFieTest(){ const filename = "test.txt" if contents, errorinfo := ioutil.ReadFile(filename) ;errorinfo != nil { //先运行前半句后进行判断 fmt.Println(errorinfo) }else { fmt.Printf("%s",contents) } } func main() { readFieTest() }
发现没有if的条件里能够进行赋值,且if条件里赋值的变量做用域就是这个if语句。接下来聊一聊switch,不少语言中都有switch。指针
switch后面是能够接表达式的(也能够不接),使用Go实现计算某两个整数的加减乘除的功能,相应的代码以下:code
package main import "fmt" func eval(a, b int,operation string) int { var result int switch operation { case "+": result = a +b case "-": result = a-b case "*": result = a*b case "/": result = a/b default: panic("不支持的运算方式"+operation) //这个panic就是报错,让程序停下来 } return result } func main() { test:= eval(3,4,"*") fmt.Println(test) } //运行结果: 12
细心的你发现什么奇特之处么?对,里面没有break
,由于Go语言中的switch
会自动break,除非使用了fallthrough
。而在C、C++或者是Java中你要么在后面添加break要么添加continue。对象
再来举一个例子,用于判断学生成绩状况:当分数小于60,则显示不及格;60-69为及格;70-79为中等;80-89为良好;90-100为优秀。使用Go语言实现的代码以下:blog
package main import "fmt" func scoreTest(score int)string { var result string = "" switch { case score <0 ||score >100 : panic(fmt.Sprintf("无效的分数:%d",score)) //若是这个条件成立,则程序再也不往下执行 case score <60: result = "不及格" case score<70: result = "及格" case score <80: result = "中等" case score <90: result = "良好" case score <=100: result = "优秀" } return result } func main() { fmt.Println( scoreTest(59), scoreTest(62), scoreTest(77), scoreTest(84), scoreTest(99), //scoreTest(-99), ) } //运行结果: 不及格 及格 中等 良好 优秀
若是程序知足panic的要求,则程序会中止运行。switch后面能够没有表达式
使用Go语言实现求解0-指定数字内的数字之和,如100之内整数的和,相应的代码以下:
package main import "fmt" func sumTest(a int) int { sum := 0 for i :=0;i<=a;i++ { sum+=i } return sum } func main() { fmt.Println(sumTest(100)) }
上面使用了for循环,能够发现这个for循环的格式除了条件中不包含括号之外,其实和Java,JavaScript的代码彻底一致。且你们要学会在函数中尽可能使用:=
的方式替代var
来声明变量。
for的条件中不包含括号,且条件中可省略初始条件,结束条件以及递增表达式
再来看一个例子,将整数转换成二进制的表达式,相应的代码以下:
package main import ( "fmt" "strconv" ) func intToBinary(n int)string { result := "" for ;n>0;n/=2{ //省略初始条件,至关于while lsb := n%2 result = strconv.Itoa(lsb) +result } return result } func main() { fmt.Println( intToBinary(5), // 101 intToBinary(13), //1101 intToBinary(121242), ) }
再来换一种方式读取以前那个test.txt文件中的内容,如今是一行行的进行读取:
//一行行读取 func printFileTest(filename string){ file, err :=os.Open(filename) if err != nil{ panic(err) //程序停下来去报错 }else{ scanner := bufio.NewScanner(file) for scanner.Scan(){ // 这里既没有开始条件,也没有递增条件,只有结束条件,此时分号均可以不写,Go语言中没有while fmt.Println(scanner.Text()) //输出 } } } func main() { printFileTest("test.txt") }
在这段代码里面for中既没有开始条件,也没有递增条件,只有结束条件,那么此时的分号均可以不写,记住Go语言中没有while。由于while的功能和for类似,因此Go语言中就没有必要存在while这个关键词了。
当for中什么也不加,则变成了一个死循环,就至关于其余语言中的while true。Go语言中的死循环实现起来很是简单,那是由于后面会常用到死循环。
简单总结一下循环语句的特色:一、for和if条件后面没有括号;二、if条件里面也能够定义变量;三、Go语言中没有while;四、switch中不须要定义break,也能够直接switch多个语句。
其实在前面咱们就使用了func
这个关键词用于定义函数,函数定义的格式为:
func 函数名称(参数名称,参数类型)返回值类型{ ...... }
须要说明的是,Go语言的函数能够有多个返回值的,且类型能够不相同:
package main import "fmt" //求解两个数的和 func sumTest(a,b int)int{ return a+b } //求两个数相除的商及余数 func divTest(a ,b int) (int,int, string) { return a/b, a%b, "你好" } func main() { fmt.Println(sumTest(3,6)) fmt.Println(divTest(13, 4)) } //运行结果: 9 3 1 你好
在上面的代码中不知道返回的究竟是什么,只知道都是int类型,其实能够像声明变量的方式那样给返回值设置名称:
//求两个数相除的商及余数 func divTest(a ,b int) (q, r int, s string) { return a/b, a%b, "你好" }
因为Go语言很是严格,定义的变量必定要使用,若是函数有多个返回值,咱们只想取某个值时,那么其他的变量可使用匿名变量_
来接收。尽管Go语言支持返回多个类型值,可是不要乱用,通常返回两个,前者是数据,后者是错误nil
,以下图所示。将前面实现两个数的四则运算的相关代码进行改写:
package main import "fmt" func calcTest(a, b int,operation string ) (int, error) { switch operation { case "+": return a+b, nil case "-": return a-b,nil case "*": return a*b,nil case "/": return a/b,nil default: return 0,fmt.Errorf("不支持的运算操做:%s",operation) } } func main() { fmt.Println(calcTest(3,5,"+")) } //运行结果: 8 <nil>
上述代码其实还不够完善,在main方法中对正常与否须要进行判断:
func main() { if result ,err:= calcTest(3,5,"+");err != nil{ //程序运行存在错误 fmt.Println("程序运行存在错误",err) }else{ fmt.Println(result) } }
在Go语言中函数能够返回多个值,且能够给多个值声明名称,可是返回多个值的状况仅仅适用于很是简单的函数,不过取不取名字和调用者无关。
Go语言是函数式编程,函数是一等公民(Python中也是),函数里面的参数,返回值里面均可以包含函数。经过前面求两个数的四则运算这个例子进行改写,实现将函数做为参数:
Go语言没有其余语言中的默认参数、可变参数、函数重载等,只有一个可变参数列表:
//求可变参数列表中参数之和 func dynamicVariable(values ... int)int { sum :=0 for i:=range values{ sum+=values[i] } return sum } func main() { fmt.Println(dynamicVariable(1,2,3,4,5,6)) } //运行结果: 21
函数小结:一、函数返回值的类型写在最后面;二、函数能够返回多个值;三、函数可做为参数进行使用;四、没有默认参数和可选参数,函数重载等。
你们不要听到指针就惧怕,Go语言中的指针和C语言中的指针差异很大(Go语言中的指针不能运算,而C语言中却能够),比C中的指针简单多了。
看到这里就必须谈到一个老生常谈的问题:Go语言中的参数传递是值传递仍是引用传递?在C和C++中既能够值传递也能够引用传递。Java和Python绝大部分都是引用传递,除了系统的自建类型之外。那么什么是值传递?什么是引用传递呢?咱们经过C++中的一段代码进行了解(C++中使用&
表示引用传递):
void pass_by_value(int a){ //值传递 a++; } void pass_by_guide(int& a){ //引用传递 a++; } int main(){ int a =3; pass_by_value(a) printf("值传递之后的值为:%d\n",a); pass_by_guide(a) printf("引用传递之后的值为:%d\n",a); } //运行结果: 3 4
pass_by_value是值传递,会将a的值从main函数中拷贝一份到pass_by_value函数中,真正做了一份拷贝,拷贝进去的a加了1,那么main函数中的a并无发生变化,没有动依旧是3。pass_by_guide是引用传递,它不会拷贝,此时main函数中的a和pass_by_guide中的a实际上是引用了同一个变量a,所以在pass_by_guide函数中进行了加1操做,天然main函数中的a也会发生变化,所以就变成了4。值传递就是拷贝,原来值不会发生变化;引用传递不会拷贝,会致使原来的值发生变化。
**Go语言只有值传递一种方式。**Go语言中的参数须要配合其指针来使用,具体分状况:
上面这种就是值传递,二者没有影响。下面是使用到了指针的状况:
左侧是一个int类型名为a的变量,右侧是一个int类型名为aa的指针,经过指针实现至关于引用传递的效果,把a的地址给了你之后,能够修改a的值。这些都是基本数据类型,再来尝试一个自定义类型:
当把左侧的book对象传给右侧的read函数时,通常这个book对象自己一般包含指向data的一个指针,而后拷贝一份到右侧函数中,右侧的book对象也有一个pdata,可是是指向同一个data,其实就是拷贝了同一份指针。所以在Go语言中,自定义类型的时候须要考虑把它做为一个值仍是一个指针来用。这里的book其实就是做为一个值来用。
用一个交换两个对象的值这个例子来加深你们的印象:
//交换两个对象的值 func swap(a,b int) { a,b = b ,a } func main() { a ,b := 1,2 swap(a,b) fmt.Println(a, b) } //运行结果: 1,2
你会发现这个函数没有用,两个数值并无发生交换,的确是这样的,那是由于这个须要借助于指针来完成:
//交换两个对象的值 func swap(a,b *int) { *a,*b = *b ,*a //声明指针须要使用* } func main() { a ,b := 1,2 swap(&a,&b) //传递地址须要使用& fmt.Println(a, b) } //运行结果: 2,1
不过这种看起来挺麻烦的,其实以前的代码不是没有起做用,而是没有将结果进行返回,修改一下代码实际上是能够的:
func swapTest(a,b int)(int ,int) { return b ,a } func main() { a ,b := 1,2 a, b = swapTest(a,b) fmt.Println(a, b) } //运行结果: 2,1
这样就经过接收函数的返回值,进而实现交换两个数值的目的。至此程序结构部分就介绍到这里,后续内容不发了,贼累,去我博客上看!