Go基础语法学习day2
数组
和c语言相同,Go语言也提供了数组类型的数据结构,数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
Go中的数组是值传递
- 声明:
var variable_name [SIZE] variable_type
var balance [10] float32
-
初始化:
- 直接进行初始化:
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} - 通过字面量在声明数组的同时快速初始化数组:
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} - 数组长度不确定,编译器通过元素个数自行推断数组长度,在[ ]中填入
...:var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}和balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} - 数组长度确定,指定下标进行部分初始化:
balanced := [5]float32(1:2.0, 3:7.0)
- 直接进行初始化:
-
在c语言中我们知道数组名在本质上是数组中第一个元素的地址,而在go语言中,数组名仅仅表示整个数组,是一个完整的值,一个数组变量即是表示整个数组。
-
数组指针:除了可以防止数组作为参数传递的时候浪费空间,还可以利用其和
for range来遍历数组
var a = [...]int{1, 2, 3} // a 是一个数组
var b = &a // b 是指向数组的指针
for i, v := range b { // 通过数组指针迭代数组的元素
fmt.Println(i, v)
}
结构体
- 声明:type用于设定结构体的名称,struct用于定义一个新的数据类型。
type struct_variable_type struct {
member definition
member definition
...
member definition
}
函数
/*函数声明
函数声明以func关键字开头,后跟functionname(函数名)。参数在()之间声明,后面是函数的returntype(返回值类型)。
参数声明的语法是参数名称后面跟类型(parametername type)。可以声明任意数量的参数:(parameter1 type, parameter2 type);如果连续的参数是同一类型的,不需要每次都写类型,只需写最后一次就可以,如(parameter1, parameter2 type)。
也可以从一个函数返回多个值:(returntype1, returntype2)。
参数和返回类型在函数中是可选的
*/
func functionname(parametername type) returntype {
//function body
}
- 可以对函数返回值命名。如果命名了返回值,可以将其视为在函数第一行中声明的变量。
/*
面积(area)和周长(perimeter)是函数的返回值,函数中的return语句没有显式地返回任何值。
由于函数声明中命名了返回值:面积(area)和周长(perimeter),所以当遇到返回语句return时,它们将自动从函数中返回。
如果连续的返回值是同一类型的,不需要每次都写类型,只需写最后一次就可以。
*/
func rectProps(length, width float64)(area, perimeter float64) {
area = length * width
perimeter = (length + width) * 2
return // 没有显式地返回值
}
包
- 主函数与主包
/*
package main 声明该源文件属于主包。
import "fmt" 用于导入包fmt,该包中包含了函数Println方法。
func main() {...} 是主函数,打印一行字符串。
*/
package main
import "fmt"
func main() {
fmt.Println("Geometrical shape properties")
}
- 导入包:
import path
/*
当前文件夹结构:
src
geometry
geometry.go
rectangle
rectprops.go
*/
package main
import (
"fmt"
"geometry/rectangle" //导入自定义包
)
func main() {
var rectLen, rectWidth float64 = 6, 7
fmt.Println("Geometrical shape properties")
//使用rectangle包中的函数
fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth))
fmt.Printf("diagonal of the rectangle %.2f ",rectangle.Diagonal(rectLen, rectWidth))
}
- 导出名称
任何以大写字母开头的变量或函数,都将在go中导出名称。
/*
只有导出的函数和变量可以从其他包中访问。我们需要从主包调用Area与Diagonal函数,所以函数名的首字母大写,导出这2个函数。
如果把rectprops.go中的Area(len, wid float64)更改为area(len, wid float64),编译器将报错。
因此,如果想从外部调用包函数,函数首字母应该大写。
*/
- 包初始化函数
- 空白标识符 _
/*
在Go中导入一个包而不使用是非法的,编译器会报错。这样可以避免未用包的膨胀,减少编译时间。
使用代码var _ = rectangle.Area消除错误。
这些类型的错误静默器在开发结束时应该删除(包括未使用的导入包)。因此,建议紧跟import语句之后,编写错误静默器。
*/
package main
import (
"geometry/rectangle"
)
var _ = rectangle.Area // 消除错误
func main() {
}
/*
有时需要初始化一个包,即使不使用包中的函数或变量。例如,我们需要初始化rectangle包(即调用它的init函数),在这种情况下也可以使用_空白标识符
*/
package main
import (
_ "geometry/rectangle"
)
func main() {
}
if
/*
与C等其他语言不同,即使在{}之间只有一条语句,{}也是强制性的
*/
if condition {
} else if condition {
} else {
}
/*
if还有一个变体,它包含一个可选的语句模块,该模块在条件求值之前执行。它的语法是
if statement; condition {
}
在xia面的程序中,num 在 if 语句中初始化。需要注意的一点是,num 只能从 if 和 else 内部访问。也就是说,num 的范围仅限于 if else 块。如果我们试图从 if 或 else 外部访问 num,编译器就会报错。
*/
package main
import (
"fmt"
)
func main() {
if num := 10; num % 2 == 0 { // 检测是否偶数
fmt.Println(num,"is even")
} else {
fmt.Println(num,"is odd")
}
}
循环
for是Go中唯一可用的循环语句。Go没有while或do while循环
-
for initialisation; condition; post { }- initialisation 初始化语句,只执行一次
- condition 条件语句
- post 后期语句将在循环的每次成功迭代后执行
先执行初始化语句,只执行一次。然后执行条件语句,检查条件,如果为true,则执行
{}中的循环体。如果循环体成功执行完毕,接着就会执行post语句。post语句执行后,将重新检查条件。如果为真,则循环将继续执行,否则for循环将终止。
在go中,初始化、条件和后期这三部分都是可选的。
在for循环中声明的变量只在循环范围内可用。所以循环体之外不能访问
i值。 -
break、continue 用法同其他语言
-
标签
/*
使用标签将外部循环从内部for循环中中断
*/
package main
import (
"fmt"
)
func main() {
outer:
for i := 0; i < 3; i++ {
for j := 1; j < 4; j++ {
fmt.Printf("i = %d , j = %d\n", i, j)
if i == j {
break outer
}
}
}
}
- for循环分号可以省略
//可以作为while循环的替代
package main
import (
"fmt"
)
func main() {
i := 0
for i <= 10 { //分号省略,只有条件存在
fmt.Printf("%d ", i)
i += 2
}
}
- for循环中声明和操作多个变量
package main
import (
"fmt"
)
func main() {
for no, i := 10, 1; i <= 10 && no <= 19; i, no = i + 1, no + 1 { //多个变量初始化,多个增量
fmt.Printf("%d * %d = %d\n", no, i, no*i)
}
}
- 无限循环
for {
}
switch
- 没有case穿透,不需要用break
- 不允许重复使用相同的常数值
package main
import (
"fmt"
)
func main() {
finger := 4
switch finger {
case 1:
fmt.Println("Thumb")
case 2:
fmt.Println("Index")
case 3:
fmt.Println("Middle")
case 4:
fmt.Println("Ring")
case 4://duplicate case
fmt.Println("Another Ring") //error
case 5:
fmt.Println("Pinky")
}
}
default不一定放在最后,它可以出现在switch语句中的任何地方
package main
import (
"fmt"
)
//switch 语句可以包含一个可省略语句,它在表达式求值之前执行,此处声明的 finger 变量作用域,仅限于 switch 语句包含的代码块。
func main() {
switch finger := 8; finger {
case 1:
fmt.Println("Thumb")
case 2:
fmt.Println("Index")
case 3:
fmt.Println("Middle")
case 4:
fmt.Println("Ring")
case 5:
fmt.Println("Pinky")
default: //default case
fmt.Println("incorrect finger number")
}
}
- case中可以包含多个表达式,用逗号分隔。
package main
import (
"fmt"
)
func main() {
letter := "i"
switch letter {
case "a", "e", "i", "o", "u": //letter匹配其中的一个就行
fmt.Println("vowel")
default:
fmt.Println("not a vowel")
}
}
- switch语句中的表达式是可选的,可以省略。如果表达式被省略,则认为
switch为true,并对每个case表达式求值,为真则执行相应的代码块。等价于多个if else子句
package main
import (
"fmt"
)
func main() {
num := 75
switch { // expression is omitted
case num >= 0 && num <= 50:
fmt.Println("num is greater than 0 and less than 50")
case num >= 51 && num <= 100:
fmt.Println("num is greater than 51 and less than 100")
case num >= 101:
fmt.Println("num is greater than 100")
}
}