1.Go 语言特色
1)简洁、快速、安全
2)并行、有趣、开源
3)内存管理、数组安全、编译迅速
2.Go 语言用途
1)Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言
2)对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。
3.第一个 Go 程序
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
go build hello.go
./hello
4.Go 语言结构
Go 语言的基础组成有以下几个部分:
1)包声明
2)引入包
3)函数
4)变量
5)语句 & 表达式
6)注释
注意
需要注意的是 { 不能单独放在一行,所以以下代码在运行时会产生错误
5.Go 语言基础语法
Go 标记
Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号
行分隔符
Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用;
注释
// 单行注释
/*
我是多行注释
*/
标识符
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字
字符串连接
Go 语言的字符串可以通过 + 实现
6.Go 语言数据类型
1)布尔型
2)数字类型
3)字符串类型:
4)派生类型:
包括:
(a) 指针类型(Pointer)
(b) 数组类型
(c) 结构化类型(struct)
(d) Channel 类型
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface)
(h) Map 类型
7.Go 语言变量
变量声明
1)var v_name v_type
2)var v_name = value
3)v_name := value
4)多变量声明
var vname1, vname2, vname3 type
8.Go 语言常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量
const identifier [type] = value
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量
const (
a = iota
b = iota
c = iota
)
9.Go 语言运算符
Go 语言内置的运算符有:
1)算术运算符
2)关系运算符
3)逻辑运算符
4)位运算符
5)赋值运算符
6)其他运算符
10.Go 语言条件语句
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" );
} else {
/* 如果条件为 false 则执行以下语句 */
fmt.Printf("a 不小于 20\n" );
}
switch marks {
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
11.Go 语言循环语句
Go 语言的 For 循环有 3 种形式
for init; condition; post { }
for condition { }
for { }
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
for sum <= 10{
sum += sum
}
sum := 0
for {
sum++ // 无限循环下去
}
12.Go 语言函数
函数定义
func function_name( [parameter list] ) [return_types] {
函数体
}
func swap(x, y string) (string, string) {
return y, x
}
13.Go 语言变量作用域
1)函数内定义的变量称为局部变量
2)函数外定义的变量称为全局变量
3)函数定义中的变量称为形式参数
14.Go 语言数组
声明数组
Go 语言数组声明需要指定元素类型及元素个数
var variable_name [SIZE] variable_type
初始化数组
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
多维数组
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引为 0 */
{4, 5, 6, 7} , /* 第二行索引为 1 */
{8, 9, 10, 11}, /* 第三行索引为 2 */
}
标题15.Go 语言指针
Go 语言的取地址符是 &
指针声明格式
var var_name *var-type
var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针
var ip *int
如何使用指针
指针使用流程:
1)定义指针变量
2)为指针变量赋值
3)访问指针变量中指向地址的值
Go 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
16.Go 语言结构体
type struct_variable_type struct {
member definition
member definition
...
member definition
}
type Books struct {
title string
author string
subject string
book_id int
}
var Book1 Books=Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407}
访问结构体成员
结构体.成员名
结构体指针
var struct_pointer *Books
17.Go 语言切片(Slice)
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片
你可以声明一个未指定大小的数组来定义切片:
var identifier []type
切片不需要说明长度。
或使用make()函数来创建切片:
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
也可以指定容量,其中capacity为可选参数。
make([]T, length, capacity)
切片初始化
s :=[] int {1,2,3 }
将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片
s := arr[startIndex:endIndex]
len() 和 cap() 函数
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
空(nil)切片
一个切片在未初始化之前默认为 nil,长度为 0
append() 和 copy() 函数
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
18.Go 语言范围(Range)
Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对
package main
import "fmt"
func main() {
//这是我们使用range去求一个slice的和。使用数组跟这个很类似
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
//range也可以用在map的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
}
19.Go 语言Map(集合)
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
定义 Map
- 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
package main
import "fmt"
func main() {
var countryCapitalMap map[string]string /*创建集合 */
countryCapitalMap = make(map[string]string)
/* map插入key - value对,各个国家对应的首都 */
countryCapitalMap [ "France" ] = "巴黎"
countryCapitalMap [ "Italy" ] = "罗马"
countryCapitalMap [ "Japan" ] = "东京"
countryCapitalMap [ "India " ] = "新德里"
/*使用键输出地图值 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [country])
}
/*查看元素在集合中是否存在 */
capital, ok := countryCapitalMap [ "American" ] /*如果确定是真实的,则存在,否则不存在 */
/*fmt.Println(capital) */
/*fmt.Println(ok) */
if (ok) {
fmt.Println("American 的首都是", capital)
} else {
fmt.Println("American 的首都不存在")
}
}
20.Go 语言递归函数
package main
import "fmt"
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-2) + fibonacci(n-1)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\t", fibonacci(i))
}
}
21.Go 语言类型转换
type_name(expression)
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %f\n",mean)
}
22.Go 语言接口
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
/* 定义接口 */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* 定义结构体 */
type struct_name struct {
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* 方法实现*/
}
package main
import (
"fmt"
)
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
23.Go 错误处理
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// 实现
}
24.Go 语言并发
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
goroutine 语法格式:
go 函数名( 参数列表 )
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
25.实例
package main
import "fmt"
func main() {
/* 这是我的第一个简单的程序 */
const constvalue = "my first "
fmt.Println("Hello, World!")
var str string = "This is a String"
fmt.Println(str)
var i, j int = 1, 2
fmt.Println(i + j)
fmt.Println(&i)
fmt.Println(constvalue)
fmt.Println("-------------------")
var a, b int = 10, 11
if a > b {
fmt.Println("a>n")
} else if a == b {
fmt.Println("a=b")
} else {
fmt.Println("a<b")
}
fmt.Println("--------------")
var sum int = 0
var num int = 0
for num = 0; num < 10; num++ {
fmt.Print("num = ")
sum += num
fmt.Println(num)
}
fmt.Println(sum)
var l = max(a, b)
fmt.Println(l)
headNode := &Node{
Data: 0,
Next: nil,
}
node1 := &Node{
Data: 1,
Next: nil,
}
node2 := &Node{
Data: 2,
Next: nil,
}
node3 := &Node{
Data: 3,
Next: nil,
}
list := headNode
Insert(node1, headNode)
Insert(node2, headNode)
Insert(node3, headNode)
PrintList(list)
fmt.Println("------------------")
root1 := &Tree{
data: 0,
right: nil,
left: nil,
}
root2 := &Tree{
data: 1,
right: nil,
left: nil,
}
root3 := &Tree{
data: 2,
right: nil,
left: nil,
}
trees := root1
add(root2, root1)
add(root3, root1)
display(trees)
}
func max(i, j int) int {
if i > j {
return i
} else if i == j {
return 0
} else {
return j
}
}
type Node struct {
Data int
Next *Node
}
func Insert(node *Node, root *Node) {
tmp := root
for tmp.Next != nil {
tmp = tmp.Next
}
tmp.Next = node
}
func PrintList(list *Node) {
p := list
for p != nil {
fmt.Printf("%d ", p.Data)
p = p.Next
}
fmt.Println()
}
type Tree struct {
data int
right *Tree
left *Tree
}
func add(tree *Tree, root *Tree) {
current := root
for {
root := current
if current.data < tree.data {
current = current.right
if current == nil {
root.right = tree
break
}
} else {
current = current.left
if current == nil {
root.left = tree
break
}
}
}
}
func display(root *Tree) {
if root != nil {
display(root.left)
fmt.Println(root.data)
display(root.right)
}
}