Go语言

参考文章 菜鸟教程

  Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。

一、环境安装

  安装包下载地址为 https://golang.org/dl/, 解压后将bin目录添加到环境变量,即可执行脚本 go run test.go

二、基础语法

Go 标记: Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号

:package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

行分隔符:一行代表一个语句结束,如果你打算将多个语句写在同一行,它们则必须使用 ; 区分,但在实际开发中我们并不鼓励这种做法。

标识符:标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母、数字、下划线组成的序列,而且标识符不能是关键字,以数字开头或包含运算符。有效的标识符: _temp、 a_123,无效的标识符:1ab、case、a+b

三、变量

1. 变量声明:

var a int = 10 // var a int; a=10; 指定变量类型,声明后若不赋值,使用默认值。
var a = 10 // 根据值自行判定变量类型。
a : = 10 // 省略var, 注意 :=左侧的变量若已经声明过会导致编译错误。这是使用变量的首选形式,但是它只能被用在函数体内,而不能用于全局变量的声明与赋值

如果你声明了一个局部变量却没有在相同的代码块中使用它,会得到编译错误。但是全局变量是允许声明但不使用。

2. 多变量声明

var a, b, c= 1, 2, 3

并行赋值也被用于当一个函数返回多个返回值时,如调用 Func1 函数得到val和err:val, err = Func1(var1)。

3. 值类型和引用类型:

  像 int、float、bool 和 string 这些基本类型都属于值类型

   一个引用类型的变量存储的是其值所在的内存地址,这个内存地址称为指针。* 表示指针变量,& 返回变量存储地址

var a int = 4
var ptr *int
ptr = &a    // ptr赋值为a变量的地址
fmt.Printf("a = %d
", a);
fmt.Printf("*ptr = %d
", *ptr);
fmt.Println("is null:", ptr == nil); // 判断是否为空指针

变量作用域

Go 语言中变量可以在三个地方声明:

  • 局部变量:函数内定义的变量,返回值变量也是局部变量。
  • 全局变量:函数外定义的变量,可以在整个包甚至外部包(被导出后)使用。
  • 形式参数:函数定义中的变量,函数参数
package main
import "fmt"

var g int = 20  // 声明全局变量
func main() {
   var g int = 10  // 声明局部变量 
   fmt.Printf ("g = %d
",  g)  // g = 10, 全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑
}

四、常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

  显式类型定义: const b string = "abc"
  隐式类型定义: const b = "abc"  // 可以省略 变量类型[type],编译器可以根据变量的值来推断其类型。

多个相同类型的声明可以简写为:const a, b= 1, 2

常量还可以用作枚举:

const (
    Unknown = 0
    Female = 1
    Male = 2
)

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:println(len(a),unsafe.Sizeof(a))

iota

  iota是go语言的常量计数器,只能在常量的表达式中使用。iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。

const a = iota // a=0 
const ( 
  b = iota     // b=0 每次 const 出现时,都会让 iota 初始化为0.
  c            // c=1 
  d = 3<<iota  // d=3<<2=12
  e            // e=3<<3=24
  d = "ha"     // d="ha", iota=4
  e            // e="ha", iota=5
  f = iota     // f=6
)

五、条件和循环语句

六、数组

1. 声明格式:var variable_name [SIZE] variable_type   

2. 数组初始化:
  var numbers = [3]int{1, 2, 3}
  var numbers = [] int{1, 2, 3}  //不设置数组大小,根据元素的个数来设置大小

3. 二维数组:

var a [3][4]int
a = [3][4]int{  
    {0, 1, 2, 3},   
    {4, 5, 6, 7},   
    {8, 9, 10, 11},  
}

4. 向函数传递数组

func main() {
   var numbers = []int {1, 2, 3, 4, 5}
   var avg float32
   avg = getAverage(numbers, 5);
   fmt.Printf("Average: %f ", avg);
}
func getAverage(arr []int, size int) float32 {
   var i,sum int
   var avg float32  
   for i = 0; i < size;i++ {
      sum += arr[i]
   }
   avg = float32(sum / size)  //类型转换
   return avg;
}

切片(slice)

  Go 语言切片是对数组的抽象。Go 数组的长度不可改变,Go提供了一种功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

切片定义:

声明一个未指定大小的数组: var identifier []type
或使用make()函数来创建切片: var slice1 []type = make([]type, len), 也可以简写为slice1 := make([]type, len)
也可以指定容量,其中capacity为可选参数。make([]T, length, capacity),这里 len 是数组的长度并且也是切片的初始长度。

切片初始化:

s :=[] int {1,2,3 }
s := arr[:]  // 切片s为数组arr的引用。 切片截取通过设置下限及上限来设置截取切片 s := arr[startIndex:endIndex] , s := arr[startIndex:] ,s := arr[:endIndex]

  s :=make([]int,len,cap) //通过内置函数make()初始化切片s

func main() {
    var x []int           // len=0 cap=0, slice=[], 一个切片在未初始化之前默认为 nil,长度为 0  
    x = make([]int,2,5)   // len=2 cap=5, slice=[0 0]
    x = append(x, 10)     // len=3 cap=5, slice=[0 0 10], 向切片添加一个元素    
    x = append(x, 11, 12) // len=5 cap=5, slice=[0 0 10 11 12], 向切片添加多个元素    
    x1 := make([]int, len(x), (cap(x))*2) //  创建切片x1是之前切片的两倍容量
    copy(x1, x)              // len=5 cap=10, slice=[0 0 10 11 12]
}
func printSlice(x []int) {
   fmt.Printf("len=%d cap=%d, slice=%v
", len(x), cap(x), x)
}

七、Map(集合)

八、结构体

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

package main
import "fmt"

type Book struct { // 结构体定义
    title string
    author string
}
func main() {
    var book1 Book
    book1.title = "Java"  // 访问结构体成员
    book1.author = "Thomas"
    printBook(book1)      // Java {Java Thomas}
    printBook_ptr(&book1) // Java &{Java Thomas}
}
func printBook(b Book) {  // 结构体作为函数参数
   fmt.Println(b.title, b)
}
func printBook_ptr(b *Book) { // 结构体指针
   fmt.Println(b.title, b)
}

九、范围(Range)

十、函数

  每一个可执行程序必须包含main() 函数,通常它是启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。

func main() {
    a, b := 1, 2
    c,d := swap(a, b)
    e := getValue(a)
    fmt.Println(c, d, e)
}
func swap(a int, b int) (int, int){ // 多个返回值
   return b, a
}
func getValue(a int) int { // 一个返回值
   return a
}

函数参数

package main
import "fmt"

func main() {
    x, y := 1, 2
    val_swap(x, y)   // 值传递 x=1 y=2
    print(x, y)       
    ref_swap(&x, &y) // 引用传递 x=2 y=1
    print(x, y)
}
func val_swap(x int, y int) { 
   var temp int
   temp = x
   x = y
   y = temp
}
func ref_swap(x *int, y *int){
    var temp int
    temp = *x
    *x = *y
    *y = temp
}
func print(x int, y int) { 
   fmt.Printf("x=%d y=%d
", x, y)
}

函数作为值

递归函数

十一、接口

十二、错误处理

原文地址:https://www.cnblogs.com/anxiao/p/8250394.html