• go基本语法 lcl


    一、main函数与package声明

      1、main 函数概览

             

       main函数要点:无参数、无返回值;main 方法必须要在 main 包里面;`go run main.go` 就可以执行;如果文件不叫 `main.go`,则需要`go build` 之后再 `go run`。

      2、package 声明

        语法形式:package xxxx,package使用字母和下划线的组合,package名称可以和文件夹不同,但是同一个文件夹下的声明必须一致。

        引入包语法形式:import [alias] xxx,如果一个包引入了但是没有使用,会报错,如果需要匿名引入:前面多一个下划线。如下图所示,如果不使用fmt包,但是引入就会报错,如果是使用下划线匿名引用,则不会报错。这里可能会有疑问,不用为什么要引用,这是因为有的时候需要使用包的init方法,因此需要匿名引用。

                    

    二、string 和 基础类型

      1、String

        String 声明:双引号引起来,则内部双引号需要使用\转义,` 引号引起来,则内部`需要\转义

        String 长度:string 的长度很特殊:用 len(str)获取的是字节长度:和编码无关;字符数量:和编码有关,用编码库来计算。       

    func main()  {
        println("hello world")
        println(len("你好")) // 输出6
        println(utf8.RuneCountInString("你好")) // 输出2
    }

         String 包:string 的拼接直接使用 + 号就可以。注意的是,某些语言支持 string 和别的类型拼接,但是golang 不可以

         String的工具包是strings, 主要方法(你所需要的全部都可以找到):查找和替换、大小写转换、子字符串相关、相等 

      2、rune 类型

        rune,直观理解,就是字符,rune 不是 byte,其本质是 int32,一个 rune 四个字节。

        rune 在很多语言里面是没有的,与之对应的是,golang 没有 char 类型。rune 不是数字,也不是 char,也不是 byte,实际中不太常用

      3、bool, int, uint, float 家族

        bool: true, false

        int8, int16, int32, int64, int

        uint8, uint16, uint32, uint64, uint

        float32, float64

      4、byte 类型

        byte,字节,本质是 uint8,对应的操作包在 bytes 上

      总结:

        golang 的数字类型明确标注了长度、有无符号,golang 不会帮你做类型转换,类型不同无法通过编译。也因此,string 只能和string 拼接,golang 有一个很特殊的 rune 类型,接近一般语言的 char 或者 character 的概念,非面试情况下,可以理解为 “rune = 字符”。

        string 遇事不决找 strings 包。

    三、变量声明 & 方法声明与调用

      1、变量声明

        var 声明变量:

          语法:var name type = value

          局部变量、包变量、块声明、驼峰命名、首字符是否大写控制了访问性,如下面的例子,如果是大写,在其他包也能访问,小写的话,不能在其他包访问,其子包也不能访问;在定义变量时,可以写变量类型,也可以不定义,golang 支持类型推断,但是如果其推断的和我们想定义的不一致,就必须明确,例如实例中的变量c

    func main()  {
        println("hello world")
        println(len("你好")) // 输出6
        println(utf8.RuneCountInString("你好")) // 输出2
    
        var a int = 16
        println(a)
    
        var b = 16
        println(b)
    
        var c uint = 16
        println(c)
    }
    
    var Global = "全局变量"
    
    var local = "包变量"
    
    var (
        First string = "abc"
        second int32 = 16
    )

         := 声明变量:

          只能用于局部变量,即方法内部。golang 使用类型推断来推断类型。数字会被理解为 int 或者 float64。(所以要其它类型的数字,就得用 var 来声明)     

        d := 17
        println(d)

         变量声明易错点:变量声明了没有使用、类型不匹配、同作用域下,变量只能声明一次,特别注意的是变量声明了没有使用的情况,也会编译不通过

         const 声明常量:首字符是否大写控制了访问性、驼峰命名、支持类型推断

    const internal = "包内可访问"
    const External = "包外可访问"

      2、方法声明

        方法声明包含四个部分:关键字 func、方法名字(首字母是否大写决定了作用域)、参数列表:[<name type>]、返回列表: [<name type>] ,如果是多返回值,可以直接使用return或者是return后带上具体返回项。   

    func main()  {
        println(Func01("zhangsan"))
        println(Func002)
        println(Func003("lisi", 20))
    }
    
    // 一个参数一个返回值
    func Func01(name string) string {
        return "返回值" + name
    }
    
    func Func002() {
        println(" no param no return !")
    }
    
    func Func003(name string, age int) (returnName string, returnAge int)  {
        returnName = "param:" + name
        returnAge = age + 10
        return
        //return returnName, returnAge
    }

         具体怎么编码,怎么规范,看个人爱好和公司规范

      3、方法调用

         就正常调用,没什么可说的,但是可以使用 _ 忽略返回值

        k := Func01("zhangsan")
        println(k)
    
        name1, age := Func003("wangyu", 30)
        println(name1)
        println(age)
        
        name, _ := Func003("lisi", 20)
        println(name)

       4、方法声明与调用总结

        golang 支持多返回值,这是一个很大的不同点

        golang 方法的作用域和变量作用域一样,通过大小写控制

        golang 的返回值是可以有名字的,可以通过给予名字让调用方清楚知道你返回的是什么

    四、最简单的Web服务器

      官方文档:

    package main
    
    import (
        "fmt"
        "log"
        "net/http"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
    }
    
    func main() {
        http.HandleFunc("/", handler)
        log.Fatal(http.ListenAndServe(":8080", nil))
    }

      最简单的 web 服务器 —— 增加几个路由

    func main() {
        http.HandleFunc("/", handler)
        http.HandleFunc("/home", home)
        http.HandleFunc("/user", user)
        http.HandleFunc("/order", order)
        log.Fatal(http.ListenAndServe(":8080", nil))
    }
    
    func home(w http.ResponseWriter, r *http.Request)  {
        fmt.Fprintf(w, "首页")
    }
    
    func user(w http.ResponseWriter, r *http.Request)  {
        fmt.Fprintf(w, "用户")
    }
    
    func order(w http.ResponseWriter, r *http.Request)  {
        fmt.Fprintf(w, "订单")
    }

       fmt 格式化输出,由于golang不允许不同类型的变量拼劲,因此需要使用 fmt 的格式化 拼接

        name := "zhangsan"
        age := 20
        // 格式化输出
        str := fmt.Sprintf("hello world %s hello world %d hahaha\n", name, age)
        println(str)

       fmt 包有完整的说明:

        掌握常用的:%s, %d, %v, %+v, %#v,不仅仅是 `fmt`的调用,所有格式化字符串的 API 都可以用;因为golang字符串拼接只能在 string 之间,所以这个包非常常用

          例如 %s 是字符串占位符,%d 是数字占位符,%v 是返回体占位符等,一般相关的描述都在goSDK对应包中的doc.go文档中

    五、数组与切片

      1、数组,语法是:[cap]type

        数组需要指定初始化长度(或者叫做容量),在定义时可以直接设置初始值,如果不设置,初始值为默认值,这里有个坑需要注意一下,虽然没有初始化内容,但是默认已经被初始化,长度和容量都是定义的长度。  

        数组支持使用arr[i]下标的形式访问元素,len 和 cap 操作用于获取数组长度(数组的len 和 cap 结果是一样的,就是数组的长度)        

    func main() {
        a1 := [3]int{1,2,3}
        print(a1)
    
        var a2 [3]int
        print(a2)
    }
    
    func print(a1 [3]int) {
        fmt.Printf("a1: %v,len: %d, cap: %d ", a1, len(a1), cap(a1))
    }

      2、切片,语法:[]type

        切片和数组的区别就是,数组需要直接指定长度,切片不需要指定。

        可以直接初始化,也可以使用make初始化:make([]type, length, capacity);可以使用arr[i] 下标的形式访问元素;使用append 追加元素、len 获取元素数量、cap 获取切片容容量;

        推荐写法:s1 := make([]type, 0, capacity) ,否则的话,使用append会直接在已有的数据后面添加。        

    func main() {
        a3 := []int{1,2,3,4}
        print2(a3)
    
        a4 := make([]int, 3, 4)
        print2(a4)
    
        a5 := make([]int, 4)
        print2(a5)
    
        a4 = append(a4, 5)
        print2(a4)
    
        a4 = append(a4, 6)
        print2(a4)
    
        fmt.Printf("%d", a4[4])
    }
    
    func print2(a1 []int)  {
        fmt.Printf("a1: %v,len: %d, cap: %d \n", a1, len(a1), cap(a1))
    }

       3、数组与切片对比

            

        通过上面对比可以看到,切片比数组功能更强大,因此遇事不决用切片,基本不会出错

       4、子切片:

        数组和切片都可以通过[start:end] 的形式来获取子切片,遵循 左闭右开原则:1. arr[start:end],获得[start, end)之间的元素;2. arr[:end],获得[0, end) 之间的元素;3. arr[start:],获得[start, len(arr))之间的元素   

        s1 := a4[1:3]
        print3(s1)
        s2 := a4[1:]
        print3(s2)
        s3 := a4[:2]
        print3(s3)

        对于使用子切片有个需要注意的地方,在没有扩容时,切片和自切片是共享底层的,但是如果切片或者自切片发生了扩容,就不再是共享底层了,因此使用子切片一般用于只读场景,不要用于写场景

    五、控制语句

      1、for

        for 和别的语言差不多,有三种形式:1. for {} ,类似 while 的无限循环;2. fori,一般的按照下标循环;3. for range 最为特殊的 range 遍历;

    func main() {
        arr := []int {1,2,3,4,5}
        forLoop(arr)
        forI(arr)
        forRange(arr)
    }
    
    func forLoop(arr []int)  {
        index := 0
        for {
            if index == 3 {
                break
            }
            fmt.Printf(" index = %d,number = %d \n", index, arr[index])
            index++
        }
    }
    
    func forI(arr []int)  {
        for i := 0; i < len(arr); i++ {
            fmt.Printf(" index = %d,number = %d \n", i, arr[i])
        }
    }
    
    func forRange(arr []int){
        for index, value := range arr{
            fmt.Printf(" index = %d,number = %d \n", index, value)
        }
    }

         break 和 continue 和别的语言一样

      2、if else

        if-else 和别的语言也差不多。这里有个比较特殊的用法,带局部变量声明的 if- else,例如下面例子的第二个if中的sub变量,只能在 if 块,或者后边所有的 else 块里面使用,脱离了 if - else 块,则不能再使用

    func ifelse(age int)  {
        if age<18{
            fmt.Printf("age < 18")
        }else {
            fmt.Printf("age >= 18")
        }
    
        if sub := age -10; sub > 10 {
            fmt.Printf("age-10=%d", sub)
        }
    }

       3、switch

        switch 和别的语言差不多,switch 后面可以是基础类型和字符串,或者满足特定条件的结构体最大的差别:终于不用加 break 了! 

        大多数时候,switch 后面只会用基础类型或者字符串       

    func chooiceFood(food string)  {
        switch food {
        case "apple":
            fmt.Printf("apple")
        case "banana":
            fmt.Printf("banana")
        default:
            fmt.Printf("other")
        }
    }

  • 相关阅读:
    转&nbsp;子查询
    260@365
    线程池
    转&nbsp;nio&nbsp;&nbsp;&nbsp;&nbsp;netty
    正则表达式匹配标签内的内容
    express接受ajax的发送post请求
    如何查看代码使用率
    ajax传文件用express的multer接住
    ajax 的post方法 的content-type设置和express里应用body-parser
    webpack4 es6转换
  • 原文地址:https://www.cnblogs.com/liconglong/p/16270274.html
Copyright © 2020-2023  润新知