基本语法
Go语言中的标记
Go程序是由各种标记组成的,标记可以是关键字,标识符,常量,字符串文字或符号。例如,以下Go语句由六个标记组成:
fmt.Println("Hello, World!")
每个标记单独表示为:
fmt
.
Println
(
"Hello, World!"
)
行分隔符
在Go程序中,行分隔符键是语句终止符。 也就是说,每个单独的语句不需要特殊的分隔符如:;
,也不需要像在C编译器放置;
作为语句终止符以指示一个逻辑实体的结束。
例如,以下是两个不同的语句:
fmt.Println("Hello, World!")
fmt.Println("I am in Go Programming World!")
注释
注释就类似在Go程序中帮助文本,并且它们被编译器忽略。 它们以/*
开始,并以字符*/
结尾,如下所示:
/* my first program comments in Go */
不能在注释中包含注释,并且不能在字符串或字符文字中出现。
标识符
Go标识符是用于标识变量,函数或任何其他用户定义项目的名称。标识符以字母A
到Z
或a
到z
或下划线_
开头,后跟零个或多个字母,下划线和数字(0
到9
)组成。
标识符 = 字母 {字母 | unicode数字}。
Go不允许在标识符中使用标点符号,例如@
, $
和 %
。 Go是一种区分大小写的编程语言。 因此,Manpower
和manpower
在Go中是两个不同的标识符。以下是一些可接受(合法)的标识符示例:
mahesh kumar abc move_name a_123
myname50 _temp j a23b9 retVal
关键词
以下列表显示Go中的保留字。这些保留字不能用作常量或变量或任何其他标识符名称。
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
Go语言的空白行
只包含空格的行,或者可能带有注释,被称为空行,Go编译器完全忽略它。
空白行是用于描述空格,制表符,换行符和注释的术语。 空格将语句的一部分与另一个语句隔开,并使编译器能够识别语句中的一个元素(例如int
)结束和下一个元素开始的位置。因此,在下面的语句中:
var age int;
在int
和age
之间必须至少有一个空格字符(通常是一个空格),以便编译器能够区分它们。 另一方面,如以下语句中:
fruit = apples + oranges; // get the total fruit
在 fruit
和=
之间,或在=
和apples
之间可不需要空格字符,但是如果想要增加可读性,那么可以随意添加。
变量
Go语言的变量声明方式与C和C++语言有明显的不同。对于纯粹的变量声明,Go语言引入了关键字var,而类型信息放在变量名之后,示例如下:
var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片
var v5 struct {
f int
}
var v6 *int // 指针
var v7 map[string]int // map,key为string类型,value为int类型
var v8 func(a int) int
var (
v1 int
v2 string
)
var v1 int = 10 // 正确的使用方式1
var v2 = 10 // 正确的使用方式2,编译器可以自动推导出v2的类型
v3 := 10 // 正确的使用方式3,编译器可以自动推导出v3的类型
指定类型已不再是必需的,Go编译器可以从初始化表达式的右值推导出该变量应该声明为哪种类型,这让Go语言看起来有点像动态类型语言,尽管Go语言实际上是不折不扣的强类型语言(静态类型语言)。
出现在:=左侧的变量不应该是已经被声明过的,否则会导致编译错误,比如下面这个写法:
var i int
i := 2
会导致类似如下的编译错误:
no new variables on left side of :=
多重赋值功能,比如下面这个交换i和j变量的语句:
i, j = j, i
多重返回和匿名变量:
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
若只想获得nickName,则函数调用语句可以用如下方式编写:
_, _, nickName := GetName()
常量
Go语言的字面常量更接近我们自然语言中的常量概念,它是无类型的。只要这个常量在相应类型的值域范围内,就可以作为该类型的常量,比如上面的常量-12,它可以赋值给int、uint、int32、int64、float32、float64、complex64、complex128等类型的变量。
-12
3.14159265358979323846 // 浮点类型的常量
3.2+12i // 复数类型的常量
true // 布尔类型的常量
"foo" // 字符串常量
通过const关键字,你可以给字面常量指定一个友好的名字:
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const (
size int64 = 1024
eof = -1 // 无类型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo", 无类型整型和字符串常量
常量定义的右值也可以是一个在编译期运算的常量表达式,比如
const mask = 1 << 3
由于常量的赋值是一个编译期行为,所以右值不能出现任何需要运行期才能得出结果的表达式,比如试图以如下方式定义常量就会导致编译错误:
const Home = os.GetEnv("HOME")
原因很简单,os.GetEnv()只有在运行期才能知道返回结果,在编译期并不能确定,所以无法作为常量定义的右值。
Go语言预定义了这些常量:true、false和iota。iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota在每个const开头被重设为0)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0
v float64 = iota * 42 // v == 42.0
w = iota * 42 // w == 84
)
const x = iota // x == 0 (因为iota又被重设为0了)
const y = iota // y == 0 (同上)
const ( // iota被重设为0
c0 = iota // c0 == 0
c1 // c1 == 1
c2 // c2 == 2
)
const (
a = 1 <<iota // a == 1 (iota在每个const开头被重设为0)
b // b == 2
c // c == 4
)
Go语言并不支持众多其他语言明确支持的enum关键字。伪枚举:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 这个常量没有导出
)
类型
Go语言内置以下这些基础类型:
- 布尔类型:bool。
- 整型:int8、byte、int16、int、uint、uintptr等。
- 浮点类型:float32、float64。
- 复数类型:complex64、complex128。
- 字符串:string。
- 字符类型:rune。
- 错误类型:error。
此外,Go语言也支持以下这些复合类型:
- 指针(pointer)
- 数组(array)
- 切片(slice)
- 字典(map)
- 通道(chan)
- 结构体(struct)
- 接口(interface)
int和int32在Go语言里被认为是两种不同的类型,编译器也不会帮你自动做类型转换:
var value2 int32
value1 := 64 // value1将会被自动推导为int类型
value2 = value1 // 编译错误
编译错误类似于:
cannot use value1 (type int) as type int32 in assignment。
使用强制类型转换可以解决这个编译错误:
value2 = int32(value1) // 编译通过
两个不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较,但各种类型的整型变量都可以直接与字面常量(literal)进行比较,比如:
var i int32
var j int64
i, j = 1, 2
if i == j { // 编译错误
fmt.Println("i and j are equal.")
}
if i == 1 || j == 2 { // 编译通过
fmt.Println("i and j are equal.")
}
在Go语言中,字符串也是一种基本类型。相比之下, C/C++语言中并不存在原生的字符串类型,通常使用字符数组来表示,并以字符指针来传递。
var str string // 声明一个字符串变量
str = "Hello world" // 字符串赋值
ch := str[0] // 取字符串的第一个字符
fmt.Printf("The length of \"%s\" is %d \n", str, len(str))
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
输出结果为:
The length of "Hello world" is 11
The first character of "Hello world" is H.
str := "Hello world" // 字符串也支持声明时进行初始化的做法
str[0] = 'X' // 编译错误