js css html

二. Go(Go基础知识)

2022-07-11  本文已影响0人  冰菓_

一. Go基础语法

变量的定义

使用var关键字,可以放在函数内,或者直接放在包内,使用var()集中定义变量,使用:=可以简化定义,但是只能在函数内使用

package main

import "fmt"

//没有全局变量的概念,使用var()这种写法/

var (
    a = 1
    b = 2
)

func variableZeroValue() {
    var a int
    var b int
    fmt.Printf("%d %q\n", a, b)
}

func variableInitialValue() {
    var a, b int = 1, 2
    fmt.Println(a + b)
}

func variableTypeDeduction() {

    var a, b, c, d = 1, false, "2", true
    //可以简写 := /
    e := "111"
    b = true
    fmt.Println(a, b, c, d, e)
}
func main() {
    fmt.Println("hello world")
    variableZeroValue()
    variableInitialValue()
    variableTypeDeduction()
    fmt.Println(a + b)
}
内建变量类型
  1. bool,string(布尔,字符串)
  2. (u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr 加u有符号整数 不加u无符号整数 如果不规定长度 int 还是 int8 还是int32 默认按照操作系统位数 来决定
  3. byte,rune byte字节 8位,rune是4个字节相当于java里的char 但是char是一个字节考虑到国际化原因rune竟可能能放下各种编码 32位 Unicode是2个字节 16位 utf-8是三个字节 24位。
  4. float32,float64,complex64,complex128 浮点数32位和64位,复数 complex64 实部和虚部 分别是 32位 (var a complex64=3 +4i) 128位以此类推。

强制类型转换
类型转换必须是强制的

func trigonometric() {
    a, b := 3, 4
    var c int
    c = int(math.Sqrt(float64(a*a + b*b)))
    fmt.Println(c)
}
常量与枚举

const数值可作为各种类型使用(var c int = int(math.Sqrt(aa + bb)))由于常亮没指定类型 它可以自己转换类型。

枚举类型
注意自增公式的使用

func enums() {
    const (
        cpp   = 1
        java  = 2
        scala = 3
        lua   = 4
    )
    fmt.Println(cpp, java, scala, lua)

    const (
        b = 1 << (10 * iota)
        kb
        mb
        gb
        tb
    )
    fmt.Println(b, kb, mb)
}
条件语句

if
注意:if 可以像其他语言中的for循环一样的表达式进行判断

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    const filename = "D:\\玩游戏和安装软件的.txt"
    //从源码中能够看到 ,"io/ioutil 下面的 ioutil.ReadFile方法会返回两个值,[]byte 文件内容,error错误信息/
    contents, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("%s\n", contents)
    }
    //if 可以像其他语言中的for循环一样的表达式进行判断/
    if contents, err := ioutil.ReadFile(filename); err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("%s\n", contents)
    }
}

switch
GO语言和其他语言对比switch会自动有break,如果我们需要执行后面的 case,可以使用 fallthrough

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,才使用Go中引入的Exception处理:defer, panic, recover。

func eavl(a, b int, op string) int {
    var re int
    switch op {
    case "+":
        return a + b
    case "*":
        return a * b
    default:
        panic("不支持的运算符" + op)
    }
    return re
}

注意可以没有expression

func grade(a int) int {
    var re = 0
    switch {
    case a <= 0:
        return 1
    case a > 0 && a <= 100:
        return a
    case a > 100:
        return 100
    default:
        fmt.Println("其他的....")
    }
    return re
}

for
注意for实现while的用法

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "time"
)

func sumTen() int {
    sum := 0
    for a := 10; a > 0; a-- {
        sum += a
    }
    return sum
}

func converToBin(n int) string {
    var re string = ""
    for ; n > 0; n /= 2 {
        lsb := n % 2
        re = strconv.Itoa(lsb) + re
    }
    return re
}

func readFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    } else {
        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            fmt.Println(scanner.Text())
        }
    }

}

func whileLike() {
    for {
        fmt.Println("死循环")
        time.Sleep(100)
    }
}

func main() {
    fmt.Println(sumTen())
    fmt.Println(converToBin(13))
    readFile("D:\\玩游戏和安装软件的.txt")
    whileLike()
}
函数
package main

import (
    "fmt"
    "math"
    "reflect"
    "runtime"
)

func div(a, b int) (int, int) {
    return a / b, a % b
}

func div1(a, b int) (q, r int) {
    return a / b, a % b
}

//函数式编程/
func apply(op func(int, int) int, a, b int) int {
    pointer := reflect.ValueOf(op).Pointer()
    name := runtime.FuncForPC(pointer).Name()
    fmt.Println(name, a, b)
    return op(a, b)
}

//返回多个参数/
func main() {
    fmt.Println(div(13, 3))
    q, r := div1(13, 3)
    fmt.Println(q, r)

    fmt.Println(apply(func(i int, i2 int) int {
        return int(math.Pow(float64(i), float64(i2)))
    }, 3, 4))
}

可变参数

func sunArgs(values ...int) int {
    sum := 0
    for i := range values {
        sum += values[i]
    }
    return sum
}
指针

值传递和引用传递?
Go语言只有值传递一种....这一块我在Java那里就没怎么搞清楚,后来学了点scala似乎搞清楚了,主要在于情景的应用

func swap(a,b int)  {
    b,a = a,b 
}
func swap1(a,b *int)  {
    *b,*a = *a,*b
}

二. 内建容器

数组(golang 一般不用的,数组是值传递)
package main

import (
    "fmt"
)

//数组是值类型
func changeArray(arr [3]int) {
    arr[0] = 100
    for k, v := range arr {
        fmt.Println(k, v)
    }
}

func changeArray1(arr *[3]int) {
    arr[0] = 100
    for k, v := range arr {
        fmt.Println(k, v)
    }
}
func main() {
    var arr1 [5]int
    fmt.Println(arr1)
    arr2 := [3]int{1, 2, 3}
    fmt.Println(arr2)
    var arr3 = [...]int{2, 4, 6}
    fmt.Println(arr3)
    var grid [5][5]int
    fmt.Println(grid)
    //遍历
    for k, v := range arr2 {
        fmt.Println(k, v)
    }
    changeArray(arr2)
    for k, v := range arr2 {
        fmt.Println(k, v)
    }
    changeArray1(&arr2)
    for k, v := range arr2 {
        fmt.Println(k, v)
    }
}
切片👍

???下面两个又什么区别,为什么这种写法[]是值传递的....(教材有误)
arr := []int{0, 1, 2, 3, 4, 5, 6, 7}
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}

解决:区分数组的声明和切片的声明方式 当使用字面量来声明切片时,其语法与使用字面量声明数组非常相似。二者的区别是:如果在 [] 运算符里指定了一个值,那么创建的就是数组而不是切片。只有在 [] 中不指定值的时候,创建的才是切片。看下面的例子:

// 创建有 3 个元素的整型数组
myArray := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
mySlice := []int{10, 20, 30}
package main

import "fmt"

func take(arr []int) {
    arr[3] = 100
}
func main() {
    arr := []int{0, 1, 2, 3, 4, 5, 6, 7}
    s := arr[2:6]
    fmt.Println(s)
    s1 := arr[2:]
    fmt.Println(s1)
    s2 := s[1:3]
    fmt.Println(s2)
    take(arr)
    fmt.Println(arr)
    fmt.Println(s1)
    fmt.Println(s2)

    arr1 := []int{0, 1, 2, 3, 4, 5, 6, 7}
    s11 := arr1[2:6]
    s22 := s11[3:5]
    fmt.Printf("len=%d cap=%d slice=%v\n", len(s11), cap(s11), s11)
    fmt.Printf("len=%d cap=%d slice=%v\n", len(s22), cap(s22), s22)

}
slice的扩展

slice可以向后扩展,但是不可以向前扩展

向slice添加元素
添加元素时如果超越cap,系统就会重新分配更大的底层数组
由于值传递的关系,必须接收append的返回值

package main

import "fmt"

func show(arr []int) {
    fmt.Println(len(arr), cap(arr))

}
func main() {
    var arr []int
    for i := 0; i < 100; i++ {
        show(arr)
        arr = append(arr, 2*i)
    }
    fmt.Println(arr)

}

Go 语言切片(Slice) | 菜鸟教程 (runoob.com)
Golang 入门 : 切片(slice) 👍

切片之所以被称为切片,是因为创建一个新的切片,也就是把底层数组切出一部分。通过切片创建新切片的语法如下:

slice[i:j]
slice[i:j:k]

其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。(看一下切片的扩展)

map

在向map中存储元素的时候,会将每个key经过hash运算,根据运算得到的hash值选择合适的hash bucket(hash桶),让后将各个key/value存放到选定的hash bucket中。如果一来,整个map将根据bucket被细分成很多类别,每个key可能会交叉地存放到不同的bucket中。所以,map中的元素是无序的,遍历时的顺序是随机的,即使两次以完全相同的顺序存放完全相同的元素,也无法保证遍历时的顺序。由于要对key进行hash计算选择hash bucket,所以map的key必须具有唯一性,否则计算出的hash值相同,将人为出现hash冲撞。在访问、删除元素时,也类似,都要计算key的hash值,然后找到对应的hash bucket,进而找到hash bucket中的key和value。Go中的map是一个指针,它的底层是数组,而且用到了两个数组,其中一个更底层的数组用于打包保存key和value。

package main

import "fmt"

func main() {
    m1 := map[int]string{
        1: "上海",
        2: "北京",
    }
    m2 := make(map[string]string)
    var m3 = map[int]string{}
    fmt.Println(m1, m2, m3)
    for _, v := range m1 {
        fmt.Println(v)
    }

    if v, Exist := m1[10]; Exist {
        fmt.Println(v)
    } else {
        fmt.Println("not exist")
    }

    delete(m1, 1)
    var _, OK = m1[1]
    fmt.Println(OK)

}
func main() {
    mf := map[int]func() int{
        1: func() int { return 10 },
        2: func() int { return 20 },
        5: func() int { return 50 },
    }
    fmt.Println(mf)  // 输出函数的指针
    a := mf[1]()     // 调用某个分支的函数
    println(a)
}

寻找最长不含有重复字符的子串

package main

import "fmt"

func take_num(st string) int {
    //字符对应的最新索引
    m := map[byte]int{}
    start := 0
    st_lenth := 0
    bytes := []byte(st)
    for i, ch := range bytes {
        // ok && lastI >= start ,ok是因为在map中存在的话就更新,与此同时lastI >= start保证了小的ch值不能小于start
        if lastI, ok := m[ch]; ok && lastI >= start {
            start = lastI + 1
        }
        if i-start+1 > st_lenth {
            st_lenth = i - start + 1
        }
        m[ch] = i
    }

    return st_lenth

}

func main() {
    fmt.Println(take_num("abcbod"))
}

三. 面对对象

结构体和方法
package main

import "fmt"

type treeNode struct {
    value       int
    left, right *treeNode
}

// 自定义工厂方法
func createTreeNode(value int) *treeNode {
    return &treeNode{value: value}
}

//为结构定义方法,显示定义和命名方法的接收者
func (node treeNode) print() {
    fmt.Println(node.value)
}

//值传递
func (node treeNode) setValue(value int) {
    node.value = value
}
func (node *treeNode) setValue1(value int) {
    node.value = value
}

// 树的遍历
func (node *treeNode) traverse() {
    if node == nil {
        return
    }
    node.left.traverse()
    node.print()
    node.right.traverse()
}

func main() {
    var r treeNode
    r = treeNode{value: 1}
    var _ = treeNode{left: new(treeNode)}
    r.left = &treeNode{}
    r.right = &treeNode{2, nil, nil}
    r.right.left = new(treeNode)
    fmt.Println(r)

    r.left.left = createTreeNode(3)
    r.print()

    fmt.Println(r.left.left)
    r.setValue(100)
    fmt.Println(r.value) //还是3
    r.setValue1(100)
    fmt.Println(r.value) //100

    r.traverse()
}
值接收者和指针接收者
  1. 要改变内容必须要使用指针接收者
  2. 结构过大也考虑指针接收者
  3. 一致性问题:如果有指针接收者,最好都是指针接收者
  4. 值/指针接收者均可接收值/指针
封装
扩展已有类型
使用内嵌来扩展已有结构

这块有点混乱....改天再看看吧...
Go学习:使用内嵌来扩展已有类型

四. 依赖管理

GOPATH和GOVENDOR
GO Mod

golang中使用GOPATH模式和GoModule

上一篇下一篇

猜你喜欢

热点阅读