1 go 命令式编程

前言

因为最近这段时间被拉去打一个程序开发的比赛,所以花几天学了一下go语言。

接下来打算把学习go的笔记更一下,后面再写一些关于go的安全编程的内容。

基本结构

包和函数

package main()
import (
	"fmt"
)
func main(){
	fmt.Println("hello world")
}

package关键字声明了代码所属的包。

在package关键字之后,代码使用了import关键字来导入自己将要用到的包。一个包可以包含任意数量的函数。

fmt包提供了用于格式化输入和输出的函数。

func关键字用于声明函数,在本例中这个函数的名字就是main。每个函数的体都需要使用大括号包围,这样go才能知道每个函数从何处开始,又在何处结束。

当我们运行一个程序的时候,它总是从 main 包的 main 函数开始运行。如果 main 不存在,编译器将报错。

每次用到被导入包的某个函数时,我们都需要在函数的名字前面加上包的名字以及一个点号作为前缀。

唯一允许的大括号放置风格

go对于大括号({})的摆放非常挑剔。左大括号 { 与func关键字位于同一行,而右大括号 } 则独占一行。这是go语言唯一允许的大括号放置风格,除此之外的其他大括号放置风格都是不被允许的。

如果用户尝试将左大括号和 func 关键字放在不同的行里面,那么go编译器将报告一个语法错误。

被美化的计算器

执行计算

注释

go语言的注释和C语言一样

单行注释

//这是单行注释

多行注释

/*
这是多行注释
*/
算术运算符

编程语言中一般通用的常规运算符。

运算符功能
+
-
*
/
%

格式化输出

Println输出函数
这个函数输出的内容会在后面加一个换行,也就是\n

fmt.Println("hello world")

Printf格式化输出函数

fmt.Printf("number: %v",10)

Printf 接收的第一个参数总是文本,第二个参数则是表达式,而文本中包含的格式化变量%v则会在之后被替换成表达式的值。

这个和C语言中的printf很相似。

%v是通用类型的意思

虽然Println会自动将输出的内容推进至下一行,但是Printf和Print却不会那么做。对于后面这两个函数,用户可以通过在文本里面放置换行符\n来将输出内容推进至下一行。

如果用户指定多个格式化变量,那么Printf函数将按顺序把它们替换成相应的值。

fmt.Printf("string: %[0]v \n number: %[1]v \n","Earth",10)

Printf除可以在句子的任意位置将格式化变量替换成指定的值之外,还能够调整文本的对齐位置。

用户可以通过指定带有宽度的格式化变量%4v,将文本的输出宽度填充至4个字符。

当宽度为正数时,空格将被填充至文本左边,而当宽度为负数时,空格将被填充至文本右边。

fmt.Printf("%10v\n",10)
//输出结果
//左边被以空格填充
        10
fmt.Printf("%-10v1\n",10)
//输出结果
//右边被以空格填充
10        1

常量和变量

常量

//基本声明
const host=24

变量

//基本声明
var dis=9633

走捷径

一次声明多个变量

每一行单独声明一个变量

var dis =560

一次声明一组变量

var(
	dis=560
	speed=1008
)

同一行声明多个变量

var dis,speed=560,1008

需要注意的是,为了保证代码的可读性,我们在一次声明一组变量或者在同一行声明多个变量之前,应该先考虑这些变量是否相关。

增量并赋值操作符

有几种快捷方式可以让我们在赋值的同时执行以下操作。

var weight=129.0
weigth*=0.37
//等效于:weight=weight*0.37

常见的有,这些概念一般其他编程语言中也有

符号功能
+=加上符号右边的值后再赋值
-=减上符号右边的值后再赋值
*=乘以符号右边的值后再赋值
/=除以符号右边的值后再赋值
%=模运算符号右边的值后再赋值

自增运算符

用户可以使用i++执行加1操作

但是go并不支持++i这种C语言中的操作。

var i=0
i++
i--

数字游戏

使用rand包来生成伪随机数

下列代码中,会显示一个110之间的数字。这个程序会先向Intn函数传入数字10以返回一个09的随机数,然后把这个数字加一并将其结果赋值给变量num。

传入给Intn函数的10会让rand生成从零开始的十个数字之间的随机数,即一个09的数字,所以如果我们要求是110则需加上一个1。

package main

import(
	"fmt"
	"math/rand"
)
func main(){
	var num = rand.Intn(10)+1
	fmt.Println(num)
}

虽然 rand 包的导入路径为math/rand,但是我们在调用 Intn 函数的时候只需要使用包名 rand 作为前缀即可,不需要使用整个导入路径。

循环和分支

真或假

布尔变量

注意,go中0和1不能作为布尔值使用。

//真
var z=ture
//假
var j=false

go语言标准库里面有好多函数都会返回布尔值。

例如如下代码

代码中使用了strings包的Contais函数来检查command变量是否包含单词"outsize",如果包含则返回为true,否则返回false

package main

import (
  "fmt"
  "strings"
)

func main(){
  var command="hello world"
  var exit=strings.Contains(command,"hello")
  fmt.Println("结果",exit)
}
//运行结果
结果 true

比较

比较运算符

符号含义
==相等
!=不相等
<小于
<=小于等于
>大于
>=大于等于
表中的运算符既可以比较文本,又可以比较数值。

比较结果返回的是布尔值。

package main

import (
  "fmt"
)

func main(){
  var num=33
  var age=num<10
  fmt.Printf("%v是否小于10:%v(true/false)\n",num,age)
}
//运行结果
33是否小于10falsetrue/false

使用if实现分支判断

如下所示,计算机可以使用布尔值或者比较条件在if语句中选择不同的执行路径。

package main

import (
  "fmt"
)

func main(){
  var command="go"
  if command=="no"{
    fmt.Println("1")
  }else if command=="go"{
    fmt.Println("2")
  }else{
    fmt.Println("3")
  }
}
//运行结果
2

这里要注意,else if 和 else 都要紧跟在前一个大括号后面,否则会报错。

else if语句和else语句都是可选的。当有多个分支路径可选时,可以重复使用else if直到满足需要为止。

逻辑运算符

基本都是编程语言通用的。

符号含义
||逻辑或
&&逻辑与
逻辑非
package main

import (
  "fmt"
)

func main(){
  var num=1000
  var bin=num>500 || (num/2==500 && num%100==10)
  if bin{
    fmt.Println("真")
  }else{
    fmt.Println("假")
  }
}
//运行结果

跟大多数编程语言一样,go也采用了短路逻辑:如果位于 || 运算符之前的第一个条件为真,那么位于 || 运算符之后的条件就可以被忽略,没有必要再对其进行求值。

&& 运算符的行为与 || 运算符正好相反:只有在两个条件都为真的情况下,运算结果才为真。

逻辑非运算符 ! 可以将一个布尔值从 false 变为 true,或者将 true 变为 false。

使用switch实现分支判断

go提供了 switch 语句,它可以将单个值和多个值进行比较。

package main

import (
  "fmt"
)
func main(){
  var command="b"
  //将命令和给定的多个分支进行比较
  switch command {
  case "a":
    fmt.Println("a")
    //使用逗号分隔多个可选值
  case "b","c":
    fmt.Println("b/c")
    //没有匹配的分支则执行
  default:
    fmt.Println("d")
  }
}

switch 语句的另一种用法是像 if…else 那样,在每个分支中单独设置比较条件。

switch 还拥有独特的 fallthrough 关键字,它可以用于执行下一个分支的代码。

与 c 和 java 等编程语言不同,go的 switch 语句执行一个条件分支后默认是不执行下一行的

package main

import (
  "fmt"
)

func main(){
  var command="b"
  //比较表达式放置到单独的分支里
  switch command {
  case "a":
    fmt.Println("a")
  case "b":
    fmt.Println("b")
    //下降至下一分支
    fallthrough
  case "c":
    fmt.Println("c")
  default:
    fmt.Println("d")
  }
}

使用循环实现重复执行

当需要重复执行同一段代码的时候,与一遍又一遍键入相同的代码相比,更好的办法是使用 for 关键字。

go语言是没有 while 循环关键字的,不过如下所示我们可以通过 for 关键字实现 while 循环。

后面会讲解 for 关键字如何实现类似于C语言中的那种形式。

package main

import (
  "fmt"
)
func main(){
  var count=10
  for count>0{
    fmt.Println(count)
    count--
  }
  fmt.Println("结束")
}
//运行结果
10
9
8
7
6
5
4
3
2
1
结束

在每次迭代开始之前,表达式 count>0 都会被求值并产生一个布尔值。当该值为 false也就是 count 变量等于 0 的时候,循环就会终止。反之,如果该值为真,那么程序将继续执行循环体,也就是被 { 和 } 包围的那部分代码。

此外我们还可以通过不为 for 语句设置任何条件来产生无限循环,然后在有需要的时候通过在循环体内使用 break 语句来跳出循环。

package main

import (
  "fmt"
)
func main(){
  var count=10
  for count>0{
    fmt.Println(count)
    count++
    if count>20{
      break
    }
  }
  fmt.Println("结束")
}
//运行结果
10
11
12
13
14
15
16
17
18
19
20
结束

变量作用域

审视作用域

变量从声明之时开始就处于作用域当中,换句话说,变量就是从那时开始变为可见的。

只要变量仍然存在于作用域当中,程序就可以访问它。然而在作用域之外访问变量就会报错。

变量作用域的一个好处是我们可以为不同的变量复用相同的名字。因为除极少数小型程序之外,程序的变量几乎不可能不出现重名。

go 的作用域通常会随着大括号 {} 的出现而开启和结束。

在下面的代码清单中,main函数开启了一个作用域,而for循环则开启了一个嵌套作用域

package main
import (
	"fmt"
	"math/rand"
)

func pmain(){
	var count = 0
	//开启新的作用域
	for count <10 {
		var num = rand.Intn(10)+1
		fmt.Println(num)
		count++
	}
	//作用域结束
}

因为对 count 变量的声明用于 main 函数的函数作用域之内,所以它在 main 函数结束之前将一致可见

在循环结束之后访问num变量将会引发编译器报错。

简短声明

简短声明为 var 关键字提供了另一种备选语法。

以下两行代码是完全等效的:

var count = 10 
count := 10

简短声明不仅仅是简化了声明语句,而且可以在无法使用 var 关键字的地方使用。

如下例代码

未使用简短声明

var count=0
for count=10;count>0;count--{
	fmt.Println(count)
}
fmt.Println(count)

在不使用简短声明的情况下,count 变量的声明必须被放置在循环之外,这意味着在循环解释之后 count 变量将继续存在于作用域。

在for循环中使用简短声明

for count := 10; count > 0; count--{
	fmt.Println(count)
}
//随着循环结束,count变量将不再处于作用域之内

简短声明还可以在 if 语句中声明新的变量

if num := rand.Intn(3);num==0{
	fmt.Println("Space Adventures")
}else if num ==1{
	fmt.Println("SpaceX")
}else{
	fmt.Println("Virgin Galactic")
}//随着if语句结束,变量将不再处于作用域之内

在switch语句中使用

switch num := rand.Intn(10);num{
case 0:
	fmt.Println("Space Adventures")
case 1:
	fmt.Println("SpaceX")
case 2:
	fmt.Println("Virgin Galactic")
default:
	fmt.Println("Random spaceline #",num)
}

作用域的范围

package main
import {
	"fmt"
	"math/rand"
}
//era变量在整个包都是可用的,相当于全局变量
var era="AD"
func main(){
	//era变量和year变量都处于作用域之内
	year := 2018

	//变量era、year和month都处于作用域之内
	switch month := rand.Intn(12)+1;month{
	case 2:
	//变量era、year、month和day都处于作用域之内
		day := rand.Intn(28)+1
		fmt.Println(era,year,month,day)
	
	//上面那个day和下面的day变量是全新声明的变量,跟上面生成的同名变量并不相同
	case 4,6,9,11:
		day := rand.Intn(30)+1
		fmt.Println(era,year,month,day)
	default:
		day := rand.Intn(31)+1
		fmt.Println(era,year,month,day)
	}//month变量和day变量不再处于作用域之内
}//year变量不再处于作用域之内

因为对 era 变量的声明位于 main 函数之外的包作用域中,所以它对于 main 包中的所有函数都是可见的。

注意:因为包作用域在声明变量时不允许使用简短声明,所以我们无法在这个作用域中使用

后言

参考书籍:Go语言趣学指南
参考课程:Go语言编程快速入门(Golang)

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值