Go:Golang Tip

时间:Feb. 1, 2020 分类:

目录:

iota的使用

  • iota在const关键字出现时将被重置为0
  • const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。
  • 使用iota能简化定义,在定义枚举时很有用。
const (
    _  = iota                   
    KB = 1 << (10 * iota) 
    MB = 1 << (10 * iota) 
    GB = 1 << (10 * iota) 
    TB = 1 << (10 * iota) 
    PB = 1 << (10 * iota) 
)

默认小数为float64

package main

import "fmt"

func main() {
    f1 := 1.2345
    fmt.Printf("%T", f1)
}

打印结果为float64

字符串相关

字符串转义

package main

import "fmt"

func main() {
    f1 := "\"\\\""
    fmt.Printf(f1)
    f2 := `"\"`
    fmt.Printf(f2)
}

第一种是通过\进行转义,第二种是直接使用飘号

字符串拼接

package main

import "fmt"

var f1 = "why"
var f2 = "wanghongyu"

func main() {
    f1 := "why2"
    f2 := "wanghongyu2"
    s := fmt.Sprintf("%s%s",f1, f2)
    fmt.Printf(s)
}

打印结果为why2wanghongyu2,这里注意

字符串分割

package main

import "strings"
import "fmt"

func main() {
    f1 := "w-h-y"
    s := strings.Split(f1, "-")
    fmt.Println(s)
    fmt.Printf("%T", s)
}

打印结果

[w h y]
[]string

字符串包含

package main

import "strings"
import "fmt"

func main() {
    f1 := "wanghongyu"
    // 包含
    s1 := strings.Contains(f1, "hong")
    // 前缀
    s2 := strings.HasPrefix(f1, "wang")
    // 后缀
    s3 := strings.HasSuffix(f1, "yu")
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

打印结果

true
true
true

字符串拼接

package main

import "strings"
import "fmt"

func main() {
    var s1 []string
    s1 = []string{"wang","hong","yu"}
    fmt.Println(strings.Join(s1, "+"))
}

打印结果

wang+hong+yu

字符串循环

package main

import "fmt"

func main() {
    f := "wanghongyu"
    for k, v := range f {
        fmt.Printf("%v %c\n", k, v)
    }
}

打印结果

0 w
1 a
2 n
3 g
4 h
5 o
6 n
7 g
8 y
9 u

字符串修改

package main

import "fmt"

func main() {
    f1 := "白萝卜"
    f2 := []rune(f1)
    f2[0] = '红'
    fmt.Println(string(f2))
}

slice相关

slice定义

package main

import "fmt"

func main() {
    s1 := [3]bool{true, true, true}
    s2 := [...]int{1, 2, 4, 8, 16}
    s3 := [5]int{0: 1, 3: 2}
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

slice遍历

package main

import "fmt"

func main() {
    s1 := [...]int{1, 2, 4, 8, 16}
    for i := 0; i < len(s1); i++{
        fmt.Println(i, s1[i])
    }
    for k, v := range s1{
        fmt.Println(k, v)
    }
}

slice没有开辟内存空间为nil

cat fudianshu.go
package main

// import "strings"
import "fmt"

func main() {
   var s1 []int
   fmt.Println(s1 == nil)
   s1 = []int{1, 2, 3}
   fmt.Println(s1 == nil)
}

打印结果

true
false

slice为连续内存

go的list是一块连续的内存,其他语言是将各种内存地址放到一个框

slice复制

package main

import "fmt"

func main() {
   s1 := []int{1, 3, 5}
   s2 := s1
   var s3 make([]int, 3, 3)
   copy(s3, s1)
   fmt.Println(s1, s2, s3)
   s1[0] = 100
   fmt.Println(s1, s2, s3)
}

slice添加元素

package main

import "fmt"

func main() {
   s1 := []int{1, 3, 5}
   fmt.Printf("len(s1): %d, cap(s1): %d\n", len(s1), cap(s1))
   s1 = append(s1, 7)
   fmt.Printf("len(s1): %d, cap(s1): %d\n", len(s1), cap(s1))
}

打印结果

len(s1): 3, cap(s1): 3
len(s1): 4, cap(s1): 6

slice删除元素

go语言中没有提供删除元素,需要用slice本身的特性来删除元素

示例删除第三个元素

package main

import "fmt"

func main() {
   s1 := []int{1, 3, 5, 7, 9}
   s1 = append(s1[:2], s1[3:]...)
   fmt.Println(s1)
   fmt.Println(cap(s1))
}

打印结果

[1 3 7 9]
5

slice排序

package main

import "fmt"
import "sort"

func main() {
   s1 := []int{3, 5, 7, 9, 1}
   sort.Ints(s1)
   fmt.Println(s1)
}

指针

package main

import "fmt"

func main() {
   n := 18
   // 取地址
   p := &n
   fmt.Println(p)
   fmt.Printf("%T\n", p)
   // 根据地址取值
   m := *p
   fmt.Println(m)
   fmt.Printf("%T\n", m)
}

打印结果

0xc420014088
*int
18
int

map

map需要make从初始化

package main

import "fmt"

func main() {
   m1 := make(map[string]int, 10)
   m1["why"] = 26
   m1["pqt"] = 25
   fmt.Println(m1)
   fmt.Println(m1["why"])
   value, ok := m1["mb"]
   if !ok {
       fmt.Println("没有key")
   }else{
       fmt.Println(value)
   }
}

打印结果

map[why:26 pqt:25]
26
没有key

map遍历

package main

import "fmt"

func main() {
   m1 := make(map[string]int, 10)
   m1["why"] = 26
   m1["pqt"] = 25
   for k, v := range m1{
       fmt.Println(k, v)
   }
}

打印结果

pqt 25
why 26

map删除元素

package main

import "fmt"

func main() {
   m1 := make(map[string]int, 10)
   m1["why"] = 26
   m1["pqt"] = 25
   for k, v := range m1{
       fmt.Println(k, v)
   }
}

打印结果

map[why:26 pqt:25]
map[why:26]

方法

创建方法

package main

import "fmt"

func f1(x int, y int) {
    fmt.Println(x + y)
}

func f2() {
    fmt.Println("f2")
}

func f3() int {
    return 3
}

func f4(x, y int) (ret int) {
    ret = x + y
    return 
}

func f5(x string, y ...int) int {
    fmt.Println(x)
    fmt.Println(y) // []int
    return 1
}

func main() {
    f1(1, 2)
    f2()
    fmt.Println(f3())
    fmt.Println(f4(3, 4))
    f5("why", 2, 3, 4)
}

打印结果

3
f2
3
7
why
[2 3 4]

defer

defer到函数执行完成后执行

package main

import "fmt"


func f(){
    fmt.Println("before")
    defer fmt.Println("111")
    defer fmt.Println("222")
    defer fmt.Println("333")
    fmt.Println("after") 
}

func main() {return
    f()
}

打印结果

before
after
333
222
111

go在底层执行函数的return语句并非一个原子操作,而是分两步,返回值赋值->return,在加上defer就变为了返回值赋值->defer->return

匿名函数

其实我想不明白既然只用一次为啥要弄个函数

panic和recover

recover只能用在defer中才能生效

package main

import "fmt"

func f1() {
    fmt.Println("f1")
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println(err)
            fmt.Println("recover")
        }
    }()
    panic("panic")

}


func f2(){
    fmt.Println("f2")
}

func main(){
    f1()
    f2()
}

打印结果

f1
panic
recover
f2

递归

示例是一个阶乘的例子

func f(n uint64) uint64 {
    if n <= 1 {
        return 1   
    }
    return n * f(n - 1)
}

func main() {
    ret := f(7)
    fmt.Println(ret)
}

打印结果

5040

struct

struct使用的连续内存

package main

import "fmt"

type x struct {
    a int
    b int
    c int
}

func main() {
    m := x{
        a: 10,
        b: 20,
        c: 30,
    }
    fmt.Printf("%p\n", &(m.a))
    fmt.Printf("%p\n", &(m.b))
    fmt.Printf("%p\n", &(m.c))

}

打印结果

0xc4200120e0
0xc4200120e8
0xc4200120f0

struct实现其他语言的构造方法

package main

import "fmt"

type persion struct {
    name string
    age  int
}

func newPersion(name string, age int) *persion {
    return &persion {
        name: name,
        age:  age,
    }
}

func main() {
    p1 := newPersion("why", 26)
    p2 := newPersion("pqt", 25)
    fmt.Println(p1)
    fmt.Println(p2)

打印结果

&{why 26}
&{pqt 25}

方法指定接收者

package main

import "fmt"

type persion struct {
    name string
    age  int
}

func newPersion(name string, age int) *persion {
    return &persion {
        name: name,
        age:  age,
    }
}

func (p *persion) newyear() {
    p.age++
}

func main() {
    p1 := newPersion("why", 26)
    fmt.Println(p1)
    p1.newyear()
    fmt.Println(p1)
}

打印结果

&{why 26}
&{why 27}

就是其他语言的类方法了,这里的p在python里就是self,在js里就是this

结构体嵌套

结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)

package main

import "fmt"

type Persion struct {
    Name string
    Age  int
    Address // 匿名嵌套结构体
}

type Address struct {
    Province string
    City     string
}

func newPersion(name string, age int, province string, city string) *Persion {
    return &Persion {
        Name: name,
        Age:  age,
        Address: Address{
               Province: province,
               City: city,
            },
    }
}

func main() {
    p1 := newPersion(
        "why",
        26,
        "hebei",
        "chengde",
    )
    fmt.Println(p1.Address.Province)
    fmt.Println(p1.City)
}

可以使用p1.Address.Provincep1.Province两种方式,前提是大的结构体内只有一个此名字段

struct实现继承

package main

import "fmt"

type Persion struct {
    Name string
    Age  int
}

type Man struct {
    Persion
    Height int   
}

func (p *Persion) newyear() {
    p.Age++
}

func main() {
    p1 := Man{}
    p1.Age = 26
    fmt.Println(p1.Age)
    p1.newyear()
    fmt.Println(p1.Age)
}

json序列化与反序列化

package main

import "fmt"
import "encoding/json"

type persion struct {
    name string
    age  int
}

func main() {
    p1 := persion{
        name: "why",
        age: 26,
    }
    // 序列化
    b, err := json.Marshal(p1)
    if err != nil {
        fmt.Printf("marshal failed, err: %v", err)
        return
    }
    fmt.Printf("%v", p1)
    fmt.Printf("%v", string(b))
    str := `{"name": "qpt", "age": 25}`
    var p2 persion
    // 反序列化
    json.Unmarshal([]byte(str), &p2)
    fmt.Printf("%v", p2)
}

接口

接口定义

package main

import "fmt"

type speaker interface{
    speak()
}

type cat struct{}
type dog struct{}

func (c cat) speak() {
    fmt.Println("miao~")
}

func (d dog) speak() {
    fmt.Println("wang~")
}

func da(x speaker) {
    x.speak()
}

func main() {
    var c cat
    var d dog
    da(c)
    da(d)
}

打印结果

miao~
wang~

使用变量也和以前一样

package main

import "fmt"

type speaker interface{
    speak()
}

type cat struct{
    aaa string
}
type dog struct{
    aaa string
}

func (c cat) speak() {
    fmt.Printf("%v~\n", c.aaa)
}

func (d dog) speak() {
    fmt.Printf("%v~\n", d.aaa)
}

func da(x speaker) {
    x.speak()
}

func main() {
    c := cat{aaa: "miao",}
    d := dog{aaa: "wang",}
    da(c)
    da(d)
}

接口也是一个类型,分两个部分,一部分存类型,另一部分存类型的值

接口嵌套

// Sayer 接口
type Sayer interface {
    say()
}

// Mover 接口
type Mover interface {
    move()
}

// 接口嵌套
type animal interface {
    Sayer
    Mover

空接口

package main

import "fmt"

func main() {
     m1 := make(map[string]interface{}, 16)
     m1["name"] = "why"
     m1["age"] = 26
     m1["hobby"] = [...]string{"唱", "跳", "rap", "篮球"}
     fmt.Println(m1)
}

打印结果

map[age:26 name:why hobby:[唱 跳 rap 篮球]]

可以用于方法的传参数

导入包

包的路径是以src为根目录

.
├── demo
│   └── main.go
└─── demopackage
    └── calc.go

calc.go

package calc

func Add(x, y int) int {
    return x + y
}

首字符大写包外可见

main.go

package main

import "fmt"
import calc "demopackage"

func main() {
     a := calc.Add(3, 7)
     fmt.Println(a)
}

匿名导入

import _ "包的路径"

匿名导入只会执行包的init方法,init方法没有参数也没有返回值

匿名导入多个包的执行顺序

交集,差集和并集

func union(slice1, slice2 []string) []string {
    m := make(map[string]int)
    for _, v := range slice1 {
        m[v]++
    }

    for _, v := range slice2 {
        times, _ := m[v]
        if times == 0 {
            slice1 = append(slice1, v)
        }
    }
    return slice1
}

//求交集
func intersect(slice1, slice2 []string) []string {
    m := make(map[string]int)
    nn := make([]string, 0)
    for _, v := range slice1 {
        m[v]++
    }

    for _, v := range slice2 {
        times, _ := m[v]
        if times == 1 {
            nn = append(nn, v)
        }
    }
    return nn
}

//求差集 slice1-并集
func difference(slice1, slice2 []string) []string {
    m := make(map[string]int)
    nn := make([]string, 0)
    inter := intersect(slice1, slice2)
    for _, v := range inter {
        m[v]++
    }

    for _, value := range slice1 {
        times, _ := m[value]
        if times == 0 {
            nn = append(nn, value)
        }
    }
    return nn
}