Go语言

1. 基本组成
组成元素: 关键字,标识符,常量,字符串,符号

关键字列表:

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

预定义标识符

append;bool;byte;cap;close;complex;complex64;complex128;uint8;uint16;uint32;uint64;uintptr;uint;int8;int16;int32;int64;int;imag;false;true;copy;float32;float64;iota;len;make;new;nil;panic;print;println;real;recover;string;true;

包声明 package main

引用 import "fmt"

函数 

func main(){//注意{不能单独放在一行

    fmt.Println("")//单独语句后面不用加分号,多个语句同一行需要加分号

}

(程序入口点 init函数->main函数)

注释 c++风格

变量命名规则: 大写字母开头对包外可见,小写字母对包外不可见

变量声明: var age int = 0;

3. 运行或构建

go build

go run XX.go

go install XX.go

4. 语言类型

基本类型 bool, int/float/complex/uint, string

特别数字类型: byte, rune(~int32), uintptr(无符号整型,用于存放一个指针)

派生类型

a. 指针 pointer

b. 数组

c. struct

d. channel

e. 函数

f. 切片

g. interface

h. Map类型

5. 变量

a. 变量声明

i. 指定变量类型 var identifier type

ii. 根据值自行判断 var v_name = value

iii. 省略var: v_name := value, 只能在函数体中出现

注意:

var s string

s:="hello world"

错误

var s string

s, s1 := "hello" ,"world"

正确

这说明:= 左侧只需要存在新变量即可

iv. var (

a int

b bool

)

一般用于声明全局变量

package main
import "fmt"
var (
    a int
)
func main(){
    a := "123"
    fmt.Println(a)
}

如果声明一个局部变量却没有使用,会得到编译错误!

b. 值类型,引用类型

基本类型属于值类型

引用类型: &i

c. _ 与python类似

6. 常量

const identifier [type] = value

例如 const b = "abc"

const b string = "abc"

const a, b = 1, 2

常量用作枚举:

const {

   Unknown = 0

   F = 1

   M = 2

}

len(), cap(), unsafe, Sizeof()等内置函数只用常量作参数时得到的结果可以用来给常量赋值

iota在遇到const后自动赋值0,随后const体内每一行常量声明都使iota增加1

package main
import "unsafe"

const (
    z = iota
    a = "a"
    b = len(a)
    c = unsafe.Sizeof(a)
    d
    e = iota
    f

    g = 1<<iota
)
func main(){
     println(z,a,b,c,d,e,f, g)//0 a 1 16 16 5 6 128
}

7 运算符

a. 算数运算符 +-*/%++--

b. 关系运算符 == != > < >= <=

c. 逻辑运算符 && || !

d. 位运算符 & | ^ << >>

e. 赋值运算符 = += -= *= /= %= <<= >>= &= ^= |=

f. &a 返回地址 *a 指针

var p *int

a := 4

p = &a

运算符优先级

^!

* / % << >> & &

+ - | ^

== != < <= >= >

&&

||

8. 控制语句

a. if 布尔表达式 {

XXX

}else{

}

注意: int类型不能直接当表达式内容

b. switch var1 {

case 1:

....

default:

...

}

或者

switch {

case 条件1:

....

default:

...

}

注意 case自带break,要继续执行,需要用fallthrough

switch len(a){
case 1:
switch{
case g > 128:
println(128)
case g > 64:
println(64)
default:
println(g)
}
default:
println("default A")
}

Type Switch

switch x.(type){

    case typeA:

...}

c. select语句-用于通信的switch语句,每个case必须是一个通信操作,发送或者接受。select随机执行一个可以运行的case,如果没有case可运行则将阻塞

 所有channel表达式都会被求值

所有被发送的表达式都会被求值

default可运行

不会重新对channel或者值计算

 

d. for支持break, goto, continue

for init;condition; post{}

for condition{}

for {}

for key,value := range oldMap {}

 

例子

package main
import "fmt"

func main(){
    numbers := [6]int{1,2,3,10}
    for i, x := range numbers{
        fmt.Printf("%d: %d\n", i, x)
    }
}

 

9. 函数

func function_name ([parameter list])[return types]{}

例如

func max(num1, num2 int) int{}

func main(){}

func swap(x, y string)(string, string){}

 

函数传参-引用传参传指针

函数变量

 

例子

package main
import "fmt"

func main(){
    numbers := [6]int{1,2,3,10}
    Square := func(x int)int{return x * x}
    for i, x := range numbers{
        fmt.Printf("%d: %d\n", i, Square(x))
    }
}

输出:

0: 1
1: 4
2: 9
3: 100
4: 0
5: 0

函数闭包 匿名函数可以直接使用函数内的变量(即使已经离开了函数作用域),类似generator,不必声明

package main
import "fmt"

func getSequence() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}

func main(){
    nextNumber := getSequence()
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    nextNumber = getSequence()
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
}

输出 

1
2
3
1
2

函数方法

方法具有接收者,接收者可以是命名类型或者结构体类型的值或者指针

func (variable_name variable_type) function_name() [return_type] {}

package main
//import "fmt"
type Circle struct{
    radius float64
}

func (c Circle) getArea() float64{
    return 3.14 * c.radius * c.radius
}

func main(){
    var c1 Circle
    c1.radius = 5
    println(c1.getArea())
}

 

10. 变量作用域

函数内:局部变量

函数外:全局变量,可以在整个包甚至外部包被导出后使用

函数定义:形式参数,会作为函数局部变量来使用??

注意:for循环内部局部变量

package main

func main(){
    var i = 10
    for i:= 0;i < 5;i++{
        println(i)
    }
    println(i)
}

输出

0
1
2
3
4
10

11. 数组

与切片相比,数组大小固定

var variable_name [SIZE] variable_type

var variable_name = [5] float32{1,2}

var variable_name =  [...] float32 {1,3} 自动计算容量

package main

func main(){
    var arr = [...]float32 {-1,-2,-3,-4,-5}
    for i:= 0;i < 5;i++{
        println(arr[i])
    }
}

多维数组

var variable_name [SIZE1][SIZE2][SIZE3]....[SIZEN] variable_type

初始化方法

package main

func prt(arr [3][2] float32){
   for i:= 0;i < 3;i++{
      println(arr[i][0])
   }
}

func main(){
   var arr = [...][2]float32 {{-1,-2},{-3,-4},{-5}}
   prt(arr)
}

越界显示exit status 2

 数组作为参数

void myFunc(param [10] int){}

void myFunc(param[3][2] int){}

注意数组与切片不同,需要传入确切大小

 

 

package main

func prt(arr [3][2] float32){
    for i:= 0;i < 3;i++{
        println(arr[i][0])
    }
}

func main(){
    var arr = [...][2]float32 {{-1,-2},{-3,-4},{-5}}
    prt(arr)
}

 

12. 指针

&a *p

空指针nil

数组指针

var pf *[MAX] type

指针数组

var ptr [MAX]*int

package main
import "fmt"

func main(){
    var arr = [][]float32 {{-1,-2},{-3,-4},{-5}}
    var parr *[][]float32 = &arr
    var arrp = []*[]float32 {&arr[0], &arr[1], &arr[2]}
    println(arr)
    println(parr)
    println(arrp)
    fmt.Println(arr)
    fmt.Println(parr)
    fmt.Println(arrp)
}

[3/3]0xc00007a000
0xc000004440
[3/3]0xc000004460
[[-1 -2] [-3 -4] [-5]]
&[[-1 -2] [-3 -4] [-5]]
[0xc00007a000 0xc00007a018 0xc00007a030]

指向指针的指针 **int

13 结构体

type struct_variable_type struct{

member definition;

member definition;

...

}

初始化

variable_name := struct_variable_type {value1, value2, ... valuen}

variable_name := struct_variable_type {key1: value1, key2: value2...}

结构体指针访问结构体成员也是使用"."

函数传递结构体时使用值传参!!

package main
import "fmt"
type Circle struct{
    radius int;
}
func changeR(c Circle){
    c.radius = 100
}
func changeR2(pc *Circle){
    pc.radius = 200
}
func main(){
    var c = Circle{10}
    fmt.Println(c)
    changeR(c)
    fmt.Println(c)
    changeR2(&c)
    fmt.Println(c)
}

输出

{10}
{10}
{200}

package main
import "fmt"
type Circle struct{
    radius int;
}
type Circles struct{
    circle Circle;
}
func changeR(cs Circles){
    cs.circle.radius = 100
}
func main(){
    var c = Circles{Circle{10}}
    fmt.Println(c)
    changeR(c)
    fmt.Println(c)
}

{{10}}
{{10}}

14. 切片

数组的抽象,长度不固定,可以追加

var identifier [] type

var slice1 [] type = make([]type, len)

slice1:= make([]type, len)

make函数可用于创建切片,语法为 make([]T, length, capacity)

s:= arr[startInd:endInd]

len(slice)

cap(slice)

slice = append(slice, 2,3,4)

copy(slice1, slice2)

15. range 用于在for循环中迭代Array,slice, channel或者map(集合)的元素,在数组和切片中返回索引和值,在map中返回key value对

for k, v := range map{}

for i, num := range nums{}

16. Map 使用hash实现的

var map_variable map[key_type] value_type;

map_variable  := make(map[key_type]valuet_type)

例如 mapa = make(map[string] string)

delete(map, key)

对不在集合中的key值输出默认元素

package main

func main(){
    countryCapitalMap := map[string]int{"France": 1, "Italy": 2}
    println(countryCapitalMap["China"])
}

输出0

17. 类型转换

typename(expression)

 

18. 接口

type interfae_name interface{

method_name1 [return_type1],
method_name2 [return_type2],

...

}

注意 实现的方法是以方法的形式,也即 func (var_name var_type) method_name (arg arg_type) [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()

}

 

19. 错误处理

a. 返回值中返回错误信息

func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // 实现
}

b. panic, recover

panic 主动抛出错误

recover 捕获错误

发生panic后,程序会从调用panic的函数位置或发生panic的地方立即返回,逐层向上执行函数的defer语句,然后逐层打印函数调用堆栈,直到被recover捕获或运行到最外层函数。多个panic只会捕捉最后一个。

recover用来捕获panic,阻止panic继续向上传递。recover()defer一起使用,但是defer只有在后面的函数体内直接被掉用才能捕获panic来终止异常,否则返回nil,异常继续向外传递。

package main
import "fmt"
func main(){
    defer func(){
        if err := recover() ; err != nil {
            fmt.Println(err)
        }
    }()
    defer func(){
        panic("three")
    }()
    defer func(){
        panic("two")
    }()
    panic("one")
}

20. 并发

a. goroutine: 轻量级线程,同一个程序中的所有goroutine共享一个地址空间,主线程不会阻塞

go 函数名(参数列表)

package main
//import "time"
var x int;
var ed [2]int;
func madd(tid int){
    for i:= 0;i < 10;i++{
        x++
        println(x)
    }
    ed[tid] = tid
}

func main(){
    go madd(1)
    go madd(2)
    println("ed[0]", ed[0])
    println("ed[1]", ed[1])
}

只输出了

ed[0] 0
ed[1] 0

package main
import "time"
var x int;
var ed [2]int;
func madd(tid int){
    for i:= 0;i < 10;i++{
        x++
        println(x)
    }
    ed[tid - 1] = tid
}

func main(){
    go madd(1)
    go madd(2)
    time.Sleep(2 * time.Second)
    println("ed[0]", ed[0])
    println("ed[1]", ed[1])
}

则能够输出

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
19
20
ed[0] 1
ed[1] 2

b. channel 用来在goroutine之间传递数据,操作符<-用于指定通道方向

声明通道: ch:= make(chan type [,capacity])

发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。

不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。

注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。

发送: ch<-v

接受: v = <-ch

package main
import "math/rand"

func randGenerator(c chan float32) float32{
	for i := 0; i < 10;i++{
		c <- rand.Float32()
	}
	return 0
}

func add(c chan float32, isEnd chan int) float32{
	var sum float32 = 0.0
	for i := 0; i < 10;i++{
		sum += <- c
		println(sum)
	}
	isEnd <- 0
	return 0
}

func main(){
	c := make(chan float32)
	isEnd := make(chan int)
	go randGenerator(c)
	go add(c, isEnd)
	endstatus := <- isEnd
	println(endstatus)
} 

 

可以用for + range遍历,用close访问

package main
import "math/rand"

func randGenerator(c chan float32) float32{
    for i := 0; i < 5;i++{
        c <- rand.Float32()
    }
    close(c)
    return 0
}

func main(){
    c := make(chan float32)
    go randGenerator(c)
    for rd := range c{
        println(rd)
    }
}

 

21. Variadic Function

Here’s a function that will take an arbitrary number of ints as arguments.
Variadic functions can be called in the usual way with individual arguments.
If you already have multiple args in a slice, apply them to a variadic function using func(slice...) like this.

package main
import "fmt"
func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}
func main() {

    sum(1, 2)
    sum(1, 2, 3)

    nums := []int{1, 2, 3, 4}
    sum(nums...)
}

 

posted @ 2019-03-16 11:40  雪溯  阅读(175)  评论(0编辑  收藏  举报