源自:Go语言教程
目录
1、Go语言初识
1.1、Go 语言用途
Go 语言被设计成一门应用于搭载Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。
学习记录:Go语言在搭载Web服务器和高性能分布式系统领域较其他语言具有更高的开发效率 。且支持并行计算 。适用于游戏服务器开发。
1.1.1第一个 Go 程序
接下来我们来编写第一个 Go程序 hello.go(Go语言源文件的扩展是 .go),代码如下:
hello.go 文件
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
要执行 Go语言代码可以使用go run 命令。
执行以上代码输出:
$ go run hello.go
Hello, World!
此外我们还可以使用go build命令来生成二进制文件:
$ go build hello.go
$ ls
hello hello.go
$ ./hello
Hello, World!
学习记录:
执行和生成二进制文件
go run hello.go
go bulid hello.go
1.2、Go语言环境
安装包下载地址为:https://golang.org/dl/。
系统 | 安装包 |
---|---|
Windows | go1.4.windows-amd64.msi |
Linux | go1.4.linux-amd64.tar.gz |
Mac | go1.4.darwin-amd64-osx10.8.pkg |
FreeBSD | go1.4.freebsd-amd64.tar.gz |
学习记录:安装基于windows的Go语言开发环境。将 e:\Go\bin目录添加到 path 环境变量中。桌面新建一个记事本文件,将以下代码输入,保存文件为hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
在相应的工作区E:/Go 执行脚本语言 go run hello.go
2、Go语言结构
2.1、行分隔符
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由Go编译器自动完成。
以下为两个语句:
fmt.Println("Hello, World!")
fmt.Println("Hello, Golang!")
学习记录:Go语言不同于C家族的其他语言,不需要;结尾
2.2、标识符
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
学习记录:标识符大小写相当于面向对象语言中的public和protected,体现为使用它的包对外是否可见。
2.2.1、空白标识符在函数返回值时的使用
package main
import "fmt"
func main() {
_,numb,strs := numbers() //只获取函数返回值的后两个
fmt.Println(numb,strs)
}
//一个可以返回多个值的函数
func numbers()(int,int,string){
a , b , c := 1 , 2 , "str"
return a,b,c
}
输出:
2 str
2.3、“{”不能单独放在一行
需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误:
package main
import "fmt"
func main()
{ // 错误,{ 不能在单独的行上
fmt.Println("Hello, World!")
}
2.4、导入包
Go 语言的包引入一般为: 项目名/包名
import "test/controllers"
可以省略import导入多个非main包
import (
"fmt"
"math"
)
2.5、更改包的别名
这里将包fmt改为别名.,代表省略模块名称,直接调用方法即可
import . "fmt"
func main (){
Println("hello,world")
}
2.6、声明
通过 const 关键字来进行常量的定义。
// 常量定义
const PI = 3.14
通过在函数体外部使用 var 关键字来进行全局变量的声明和赋值。
// 全局变量的声明和赋值
var name = "gopher"
通过 type 关键字来进行结构(struct)和接口(interface)的声明。
// 一般类型声明
type newType int
// 结构的声明
type gopher struct{}
// 接口的声明
type golang interface{}
通过 func 关键字来进行函数的声明。
// 由main函数作为程序入口点启动
func main() {
Println("Hello World!")
}
学习记录:type用法和全局变量的用法
3、Go基础语法
学习记录:这一部分是每个语法都会涉及的基础,简单过一遍,通过一个个例子来学习,并将不同于C语言家族的部分加以强调
3.1、标识符
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
如:
mahesh kumar abc move_name a_123
myname50 _temp j a23b9 retVal
学习记录:标识符的第一个字符不能是数字
3.2、字符串连接
Go 语言的字符串可以通过 + 实现:
package main
import "fmt"
func main() {
fmt.Println("Google" + "Runoob")
}
输出:
GoogleRunoob
学习记录:这个和 Java 类似
3.3、格式化字符串
package main
import "fmt"
func main() {
fmt.Println(fmt.Sprintf("Code=%d&endDate=%s",123,"2020-12-31"))
}
输出:
Code=123&endDate=2020-12-31
3.4、数字类型
Go 也有基于架构的类型,例如:int、uint 和 uintptr。
序号 | 类型和描述 |
---|---|
uint8 | 无符号 8 位整型 (0 到 255) |
uint16 | 无符号 16 位整型 (0 到 65535) |
uint32 | 无符号 32 位整型 (0 到 4294967295) |
uint64 | 无符号 64 位整型 (0 到 18446744073709551615) |
int8 | 有符号 8 位整型 (-128 到 127) |
int16 | 有符号 16 位整型 (-32768 到 32767) |
int32 | 有符号 32 位整型 (-2147483648 到 2147483647) |
int64 | 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
浮点型
序号 | 类型和描述 |
---|---|
float32 | IEEE-754 32位浮点型数 |
float64 | IEEE-754 64位浮点型数 |
complex64 | 32 位实数和虚数 |
complex128 | 64 位实数和虚数 |
以下列出了其他更多的数字类型:
序号 | 类型和描述 |
---|---|
byte | 类似 uint8 |
rune | 类似 int32 |
uint | 32 或 64 位 |
int | 与 uint 一样大小 |
uintptr | 无符号整型,用于存放一个指针 |
学习记录:complex,rune,uintptr三项新认识,分别表示实数或虚数、int32和 无符号整数指针
3.5、变量
①、多变量赋值
示例1:
package main
import . "fmt"
func main() {
var a string = "Runoob"
Println(a)
var b, c int = 1, 2
Println(b, c)
}
输出:
Runoob
1 2
②、默认初始化
示例2:
package main
import "fmt"
func main() {
// 声明一个变量并初始化
var a = "RUNOOB"//根据值自行判定变量类型。
fmt.Println(a)
// 没有初始化就为零值
var b int
fmt.Println(b)
// bool 零值为 false
var c bool
fmt.Println(c)
//字符串 零值为“” (空字符串)
var d string
fmt.Println(d)
}
输出:
RUNOOB
0
false
③、声明变量
intVal := 1 相等于:
var intVal int
intVal =1
3.6、常量
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
①、常量可以用作枚举:
const (
Unknown = 0
Female = 1
Male = 2
)
数字 0、1 和 2 分别代表未知性别、女性和男性。
②、常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:
实例:
package main
import "unsafe"
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
func main(){
println(a, b, c)
}
输出:
abc 3 16
③、iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota用法:
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
输出 :
0 1 2 ha ha 100 100 7 8
再看个有趣的的 iota 实例:
package main
import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
输出:
i= 1
j= 6
k= 12
l= 24
iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。
简单表述:
i=1:左移 0 位,不变仍为 1。
j=3:左移 1 位,变为二进制 110,即 6。
k=3:左移 2 位,变为二进制 1100,即 12。
l=3:左移 3 位,变为二进制 11000,即 24。
3.7、运算符
有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:
优先级 | 运算符 |
---|---|
5 | * / % << >> & &^ |
4 | + - |
3 | == != < <= > >= |
2 | 逻辑与运算 |
1 | 逻辑或运算 |
3.8、条件语句
①、if…else
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
②、switch
switch var1 {
case val1:
...
case val2:
...
default:
...
}
③、select
select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个 Channel 的收发操作。
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。
Go 编程语言中 select 语句的语法如下:
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
学习记录:注意条件不带()
3.9、循环语句
①、for循环
计算 1 到 10 的数字之和:
package main
import "fmt"
func main() {
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}
输出结果为:
55
②、For-each range 循环
这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。
package main
import "fmt"
func main() {
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}
输出:
0 google
1 runoob
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
学习记录:For-each range 循环可以同时获取值和序号
3.10、函数
①、Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
func:函数由 func 开始声明
function_name:函数名称,参数列表和返回值类型构成了函数签名。
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下return_types 不是必须的。
函数体:函数定义的代码集合。
以下实例为 max() 函数的代码,该函数传入两个整型参数 num1 和 num2,并返回这两个参数的最大值:
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
输出:
200
②、函数返回多个值
Go 函数可以返回多个值,例如:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
输出:
Runoob Google
③、函数参数
函数如果使用参数,该变量可称为函数的形参。
形参就像定义在函数体内的局部变量。
调用函数,可以通过两种方式来传递参数:
传递类型 描述
- 值传递 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
- 引用传递 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数
学习记录:默认情况下是值传递,调用过程中不会影响实参;可以返回多个值。函数调用结果可以作为另一个函数的实参。
3.11、闭包
Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
以下实例中,我们创建了函数 getSequence() ,返回另外一个函数。该函数的目的是在闭包中递增 i 变量,代码如下:
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
输出:
1
2
3
1
2
学习记录:闭包是匿名函数,可在动态编程中使用
先更新到这里,剩余部分本周择时学习
剩余部分为
- 数组
- 指针
- 结构体
- 切片
- Range
- Map
- 递归
- 类型转换
- 语言接口
- 错误处理
- 并发
- go语言开发工具