1. 意识 HelloWorld
在后面的《Go 的装置和应用》这篇文章中曾经写过 HelloWorld.go
了,当初就来逐行认识一下它。
package main
import "fmt"
func main() {fmt.Println("Hello, World!")
}
第 1 行:咱们的 Go 程序是由 包——package
形成的,包的申明模式为:package < 包名 >
。该行的意思是:以后 HelloWorld.go
文件属于 main
包。
第 2 行:如果你应用过 Java 或 Python,那你对 import 必定不生疏。该行的意思是:导入一个名为 fmt
的包。如果须要导入多个包,有两种写法:
import "fmt"
import "math"
或者应用分组模式同时导入多个包
import (
"fmt"
"math/rand"
)
显然第二种应用括号,以分组的模式导入更加不便。
第 3 行:咱们应用 func
关键字来申明一个函数,在这个例子中,咱们申明的是 main
函数。如果你有过其余语言的编程教训,必定相熟 main
函数的作用:程序的入口。
第 4 行:咱们的函数内容放在函数的 {}
中,在该例中,调用了 fmt
包中的打印办法,由此可见,Golang 语言调用函数的办法和 Java、Python 一样应用小数点:< 包名 >.< 函数名 >
。
看完这几行简略代码,咱们发现:在 Go 语言中,并不需要分号 ;
来完结语句。
2. 变量
2.1. 命名标准
Go 语言要求标识符以一个字母或下划线结尾,前面能够跟任意数量的字母、数字、下划线。不能应用关键字作为标识符
辨别大小写,变量 num
和变量 Num
是两个变量。
2.2. 申明
Go 语言的变量申明形式和其余语言(如 C、Java、Python)不太一样。
比方,咱们申明一个为 int 类型的变量 a:
var a int
能够看出,Go 语言申明变量的形式为:
var < 变量名 > < 变量类型 >
咱们还能够同时申明多个类型雷同的变量:
var < 变量名 1 >, < 变量名 2 >, < 变量名 3 >, ... < 变量类型 >
应用分组同时申明多个类型不同的变量:
var (
< 变量名 1 > < 变量类型 1 >
< 变量名 2 > < 变量类型 2 >
< 变量名 3 > < 变量类型 3 >
...
)
上面是一个具体的例子:
package main
import "fmt"
var i bool// 类型在后
func main() {
var a, b, c int// 多个
fmt.Println(i, a, b, c)
}
2.3. 初始化
当咱们申明变量时,能够对其进行初始化。当有初始值时,咱们能够省略变量的类型,变量会依据对应的初始值获取正确的类型。见下例:
package main
import "fmt"
var a int = 1
var b, c bool = true, false
func main() {
var i, j, k = 2, false, "行小观" // 省略变量类型
fmt.Println(a, b, c, i, j, k)
k = "行小观 2 号" // 赋值操作
fmt.Println(k)
}
若咱们在申明变量时,不给变量赋初始值,则这些变量会被赋予“零值”。
这些零值为:
- 数值类型为 0
- 布尔类型为 false
- 字符串为 ””(即空字符串)
如果上例中的代码中的变量不进行初始化,即:
package main
import "fmt"
var a int
var b, c bool
func main() {
var i int
var j bool
var k string
fmt.Println(a, b, c, i, j, k)
}
则打印后果为:0 false false 0 false(变量 k 因为是空字符串,所以打印进去了然而看不到)
2.4. 短变量申明
后面介绍了当咱们申明变量时有以下几种形式:
var i int // 申明一个 int 变量
var i, j, k int // 同时申明多个 int 变量
var i int = 1 // 申明一个 int 变量并初始化
var i, j, k int = 1, 2, 3 // 同时申明多个 int 变量并别离初始化
var i = 1 // 省略类型,申明一个 int 变量并初始化
var i, j, k = 1, 2, 3 // 省略类型,同时申明多个 int 变量并别离初始化
除此之外还有一种更简洁的申明变量的形式:
i := 1
i, j, k := 1, 2, 3
当咱们应用 :=
申明变量时,不必写 var
也不必写类型,然而这种形式 只能在函数外部应用,不能在函数内部应用。当在函数内部申明变量时,只能应用var
。
package main
import "fmt"
var a int = 1 // 函数内部
func main() {
var i, j int = 2, 3 // 函数外部
k := 4 // 只能在函数中应用
v1, v2, v3 := true, false, "行小观"
fmt.Println(a, i, j, k, v1, v2, v3)
}
此外,咱们申明的变量必须要应用,如果申明了变量,然而没应用,会在编译时报错。比方:
package main
import "fmt"
func main() {
var i bool
var j int // 申明了,但没应用,会报错
fmt.Println(i)
}
对于咱们导入的包也有此要求,即:导入的包必须应用。
3. 数据类型
3.1. 布尔类型
布尔类型为 bool
,值可取true
或false
,默认值为false
。
3.2. 字符串类型
字符串类型为string
,默认为空字符串""
。
3.3. 数值类型
整数类型分为:
- 有符号数:
int
、int8
、int16
、int32 (rune)
、int64
- 无符号数:
uint
、uint8 (byte)
、uint16
、uint32
、uint64
、
其中 int
和uint
的两种类型的长度雷同,取决于具体的编译器,比方在 32 位零碎上通常为 32 位,在 64 位零碎上通常为 64 位。
像 int8
、uint8
这些类型则是 Go 语言间接定义好位数的类型。rune
、byte
是 int32
、uint8
的别名。
当咱们须要应用整数时,该当尽量应用
int
类型。当然,如果你有非凡的理由应用其余整数类型,便另当他论。
浮点数类型有两种:float32
和 float64
,留神没有所谓的float
类型。
复数类型也有两种:complex64
和complex128
留神:不同类型的变量之间不能间接进行赋值或其余运算(比方加减乘除)
package main
import "fmt"
var (
a int = 1
b int8 = 2
c int16
)
func main() {c = b // 不同类型之间进行赋值操作,[报错 1]
d := a + b // 不同类型之间进行相加运算,[报错 2]
fmt.Printf("c = %v, d = %v", c, d)
}
以上代码在编译过程中会报错:
[报错 1]:cannot use b (type int8) as type int16 in assignment
[报错 2]:invalid operation: a + b (mismatched types int and int8)
3.4. 类型转换
后面一节说过:不同类型的变量之间不能间接进行赋值或其余运算,所以咱们能够间接地做。
比方:将 int8
类型转换为 int
类型,这样就能够间接地进行赋值和其余运算。
应用表达式 T(v)
将变量 v 的值的类型转换为 T 。留神是转换的是 变量的值,变量自身的类型不变。
package main
import "fmt"
var (
a int = 1
b int8 = 2
c uint
d int64
)
func main() {c = uint(b) // 将变量 b 的值 2 的类型从 int8 转换为 uint
d = int64(a) + int64(b)
fmt.Printf("c(%T):%v = b(%T):%v\n", c, c, b, b)
fmt.Printf("a(%T):%v + b(%T):%v = d(%T):%v\n", a, a, b, b, d, d)
}
留神:Go 语言中的类型转换是显示的,表达式 T()
是必须的,不能省略。
4. 常量
常量是固定的值,值在程序运行期间不会扭转。
常量能够定义为数值、字符串、布尔类型
常量的申明形式和变量差不多,区别在于常量须要用 const
关键字润饰,不能应用 :=
进行申明。
package main
import "fmt"
const num int = 555
var a int = 1
func main() {
const world = "世界"
const truth = true
fmt.Println("Hello,", world)
fmt.Println("num =", num)
fmt.Println("a =", a)
fmt.Println("对吗?", truth)
}
5. 初识函数
如果你之前学习过 C 或者 Java 等语言,必定曾经对函数(办法)有了肯定的意识。
简略地来说,函数是对能实现某个性能的局部代码的形象。当当前再须要该性能,咱们只须要调用其对用的函数即可,不用再反复编写代码。
5.1. 函数的申明
咱们在后面的内容曾经应用到了函数,即 main()
。咱们应用func
关键字申明函数。
func func_name() {}
5.2. 函数的参数
Go 语言中,函数能够有 0 个或多个参数。
package main
import "fmt"
func printName(name string, age int) {fmt.Println("我叫", name, ", 往年", age, "岁了")
}
func sayHello() {fmt.Println("行小观说:“你好”")
}
func main() {printName("行小观", 1)
sayHello()}
如果你有多个参数的类型雷同,你能够进行简写,只须要在这几个雷同的参数最初写一遍类型即可。
func foo(x int, y int, z int)
能够简写为:func foo(x, y, x int)
5.3. 函数的类型和返回值
函数的类型在函数名之后。(尽快适应 Go 的这种格调:类型在变量名后)
package main
import "fmt"
func add(x int, y int) int {return x + y}
func main() {fmt.Println(add(1, 2))
}
当函数没有返回值时,不须要写函数的类型:
func sayHello() {// 没有返回值,不写函数类型
fmt.Println("行小观说:“你好”")
}
函数能够有 0 个或多个返回值。
多个返回值就意味着该函数有多个返回值类型:
package main
import "fmt"
func sumAndDiff(x, y int) (int, int) { // 两个返回值类型
sum := x + y
diff := x - y
return sum, diff // 两个返回值
}
func main() {a, b := sumAndDiff(5, 1)
fmt.Println(a, b)
}
留神:和参数不同,有几个返回值就写几个返回值类型,不能简写。
Go 语言还提供了另一种函数返回的形式:命名返回值。
顾名思义,咱们通过给返回值进行命名,应用空 return
语句,这样会间接返回已命名的返回值。如上例的 sumAndDiff
函数能够写为:
func sumAndDiff(x, y int) (sum int, diff int) {// 提前命名返回值
sum = x + y
diff = x - y // 返回值在函数中被初始化
return // 返回值曾经初始化了,不须要再在 return 语句中写变量了
}
上面总结一下函数的应用:
func functionName(input1, input11 type1, input2 type2 ...) (type1, type11, type2 ...){
// 函数体
return value1, value11, value2 ...
}
或者命名返回值
func functionName(input1, input11 type1, input2 type2 ...) (output1 type1, output11 type11, output2 type2 ...){
// 函数体
output1 = ...
output11 = ...
output2 = ...
...
return
}
6. 导出名
后面咱们曾经应用了 import
导入 性能,比方improt "fmt"
,该行代码能够让咱们在本包中应用其余包里的函数。
那么咱们如何让其余包可能应用到本包的办法或变量呢?答案是:将办法或变量 导出。
在 Go 语言中,如果一个名字以大写字母结尾,那么它就是已导出的,这意味着别的包能够应用它。(相当于 Java 中的 public
的作用)
比方咱们罕用的打印函数 fmt.Println(...)
,能够看到Println()
的首字母是大写的,所以咱们可能导入 fmt
包后应用该办法。
7. 流程管制语句
7.1. if 语句
if 语句是条件判断语句,用来判断是否满足某种条件,如果满足,则执行某段代码;如果不满足,则不执行。
if ... {// 代码} else if ... {// 代码} else {// 代码}
留神格局:条件判断语句 不须要 应用小括号()
。
上面是几个例子:
if a > 0 {// 如果满足 a >0,则打印 Hello, World
fmt.Println("Hello, World")
}
if a > 0 {// 如果满足 a >0,则打印 Hello, World
fmt.Println("Hello, World!")
} else {// 否则(即不满足 a >0), 则打印 你好,世界!fmt.Println("你好,世界!")
}
if a > 5 {// 如果满足 a >5,则打印 Hello, World
fmt.Println("Hello, World!")
} else if a <= 5 && a > 0 {// 如果满足 0 <a<=5,则打印 好好学习,天天向上
fmt.Println("好好学习,天天向上")
} else {// 否则(即下面的条件都不满足),则打印 你好,世界!fmt.Println("你好,世界!")
}
Go 语言的 if 语句有一个个性:能够在条件表达式前执行一个简略的语句。上面是一个例子:
package main
import "fmt"
func sum(x, y int) int {return x + y}
func main () {if i := sum(1, 2); i > 0 {fmt.Println("Hello, World!")// 作用域内,能打印 i
}
//fmt.Println(i)// 作用域外,不能打印 i
}
在 if 语句中,应用 sum(x, y int)
函数计算出 i 的值,再进行判断。留神:变量 i 的作用域只在 if 语句中无效。
7.2. for 语句
for 语句是 Go 语言中的循环管制语句。它有几种模式:
(一)根本模式:
for 初始化语句; 条件表达式; 后置语句 {// 循环体代码}
- 初始化语句:在第一次循环前之前,且只执行这一次
- 条件表达式:每次循环都会计算该表达式,如果满足(值为 true)则持续循环;如果不满足(值为 false),则跳出循环
- 后置语句:每次循环执行完都会执行该语句
上面是一个例子,循环打印 5 次 ”Hello,World!”
for i := 0; i < 5; i++ {fmt.Println("Hello, World!", i)
}
留神该例的初始化语句 i := 0
是一个短变量申明,变量 i 只在该 for 循环中失效。
(二)省略模式:
for 循环中的初始化语句和后置语句是能够省略的。
i := 0
for ; i < 5; i++ {fmt.Println("Hello, World!", i)
}
i := 0
for ; i < 5; {fmt.Println("Hello, World!", i)
i++
}
从某种意义上来讲,下面两个例子并没有省略初始化语句或后置语句,只是扭转了地位。
(三)while 模式
诸如 C、Java 等语言中都有 while 循环,然而 Go 语言中没有 while 循环,然而咱们能够应用 for 循环来实现“while 循环”。
其实 (二)省略模式
中的第二个 for 循环例子就曾经能够看做是 while 循环了。咱们再稍做改良:
i := 0
for i < 5 {// 去掉两个分号,只写条件表达式
fmt.Println("Hello, World!", i)
i++
}
(四)有限循环模式
// 打印有限多个 Hello, World!
for {fmt.Println("Hello, World!")
}
7.3. break 和 continue
下面提到的循环语句只有当条件表达式的值为 false 时,才会进行循环。但理论开发中,咱们可能在条件表达式的值为 true 的状况下,须要退出循环。这种时候,就须要应用 break
或continue
语句。
break
语句用来跳出以后循环,continue
语句用来跳过本次循环。
上面是两个实例(改良下面循环打印 5 次 ”Hello,World!” 的例子):
实例 1:减少需要,当打印完第 2 遍 Hello,World!
时,进行打印
for i := 0; i < 5; i++ {
if i == 2 {break}
fmt.Println("Hello, World!", i)
}
实例 2:减少需要,不打印第 3 遍Hello,World!
for i := 0; i < 5; i++ {
if i == 2 {continue}
fmt.Println("Hello, World!", i)
}
7.4. switch 语句
咱们能够应用 if…else if…else if… 进行一连串的条件判断,然而这样过于繁冗。switch 语句就是用来简化这个问题的。
switch 变量 {
case 选项 1 :
// 操作 1 代码
case 选项 2 :
// 操作 2 代码
case 选项 3 :
// 操作 3 代码
case 选项 n:
// 操作 n 代码
default :
// 默认操作
}
switch
语句中有许多 case
和一个 default
,只有当变量和 case 的选项相匹配时,才会执行对应的操作代码。如果没有 case 的选项能够匹配,则默认执行default
的代码。
上面是一个例子:
package main
import "fmt"
func sum(x, y int) int {return x + y}
func main () {result := sum(3, 2)
switch result {
case 1 :
fmt.Println("后果为 1")
case 2, 3, 4: // 多种状况聚合在一起
fmt.Println("后果为 2 或 3 或 4")
case sum(1, 4): // 反对表达式
fmt.Println("后果为 5")
default:
fmt.Println("其余后果")
}
}
从下面的例子能够看出,Go 语言中 switch 的 case 反对常量(不用为整数)、表达式、多个值聚合。留神:不论是常量、表达式,还是多个值聚合,都要保障常量、表达式的值、多个值的类型和 switch 的变量雷同。
switch 语句的匹配程序是自上到下。Go 语言主动为每个 case 提供了 break 语句,所以在泛滥选项中只能执行 1 个 case
或default
,而后完结,残余的不再执行。
然而能够应用 fallthrough
强制执行残余的 case:
result := sum(1, 1)
switch result {
case 1 :
fmt.Println("后果为 1")
fallthrough
case 2, 3, 4:
fmt.Println("后果为 2 或 3 或 4")
fallthrough
case sum(1, 4):
fmt.Println("后果为 5")
fallthrough
default:
fmt.Println("其余后果")
}
还是下面的那个例子,然而在每个 case 中应用fallthrough
,当初的打印后果为:
后果为 2 或 3 或 4
后果为 5
其余后果
如有谬误,还请斧正。
文章首发于公众号『行人观学』