zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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...)
    }
  • 相关阅读:
    根据自己的博客数据统计国内IT人群
    使用dropwizard(5)--加入swagger
    使用dropwizard(4)-加入测试-jacoco代码覆盖率
    使用dropwizard(3)-加入DI-dagger2
    收藏博客
    IntelliJ IDEA 下载安装(含注册码)
    fontawesome图标字体库组件在服务器上显示不出来图标的解决
    MySQL DBA工作角色和职责介绍
    MySQL主主复制(双主复制)配置过程介绍
    MySQL表与表之间的SQL Joins图介绍
  • 原文地址:https://www.cnblogs.com/xuesu/p/10541535.html
Copyright © 2011-2022 走看看