Golang

238 阅读5分钟

go mod

go env -w GOPROXY=https://goproxy.io

交叉编译

待更新

接口使用扫盲

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。

log/logInterface.go

package log

type LogInterface interface {
	LogDebug(message string)
	LogWarn(message string)
	LogError(message string)
}

file.go

package log

import "fmt"

type FileLog struct {}

func NewFileLog() LogInterface {
	return &FileLog{}
}

func (f *FileLog) LogDebug(message string) {
	fmt.Printf("file %s\n", message)
}

func (f *FileLog) LogWarn(message string) {
	fmt.Printf("file %s\n", message)
}

func (f *FileLog) LogError(message string) {
	fmt.Printf("file %s\n", message)
}

console.go

package log

import "fmt"

type ConsoleLog struct {}

func NewConsoleLog() LogInterface {
	return &ConsoleLog{}
}

func (c *ConsoleLog) LogDebug(message string) {
	fmt.Printf("console %s\n", message)
}

func (c *ConsoleLog) LogWarn(message string) {
	fmt.Printf("console %s\n", message)
}

func (c *ConsoleLog) LogError(message string) {
	fmt.Printf("console %s\n", message)
}

main.go

package main

import "test/log"

func main() {
	mylog := log.NewFileLog()
	mylog.LogDebug("this is a debug log...")
	mylog.LogWarn("this is a warning log...")
	mylog.LogError("this is a error log...")

	mylog2 := log.NewConsoleLog()
	mylog2.LogDebug("this is a debug log...")
	mylog2.LogWarn("this is a warning log...")
	mylog2.LogError("this is a error log...")
}

读写文件

读文件第一种方法

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	f, err := os.Open("test.go")
	if err != nil {
		log.Fatal(err)
	}

	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", data)
}

第二种方法(一次读取所有内容)

package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

func main() {
	data, err := ioutil.ReadFile("test.go")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", data)
}

逐行读取文件

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	f, err := os.Open("test.go")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	reader := bufio.NewReader(f)
	for {
		line, _, err := reader.ReadLine()
		if err == io.EOF {
			break
		}

		fmt.Printf("%s\n", line)
	}
}

写文件

文件打开方式

//打开方式
const (
	//只读模式
	O_RDONLY int = syscall.O_RDONLY // open the file read-only.
	//只写模式
	O_WRONLY int = syscall.O_WRONLY // open the file write-only.
	//可读可写
	O_RDWR int = syscall.O_RDWR // open the file read-write.
	//追加内容
	O_APPEND int = syscall.O_APPEND // append data to the file when writing.
	//创建文件,如果文件不存在
	O_CREATE int = syscall.O_CREAT // create a new file if none exists.
	//与创建文件一同使用,文件必须存在
	O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
	//打开一个同步的文件流
	O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
	//如果可能,打开时缩短文件
	O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
)

打开模式

//打开模式
const (
	ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory 文件夹模式
	ModeAppend // a: append-only 追加模式
	ModeExclusive // l: exclusive use 单独使用
	ModeTemporary // T: temporary file (not backed up) 临时文件
	ModeSymlink // L: symbolic link 象征性的关联
	ModeDevice // D: device file 设备文件
	ModeNamedPipe // p: named pipe (FIFO) 命名管道
	ModeSocket // S: Unix domain socket Unix 主机 socket
	ModeSetuid // u: setuid 设置uid
	ModeSetgid // g: setgid 设置gid
	ModeCharDevice // c: Unix character device, when ModeDevice is set Unix 字符设备,当设备模式是设置Unix
	ModeSticky // t: sticky 粘性的
	// Mask for the type bits. For regular files, none will be set. bit位遮盖.不变的文件设置为none
	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
	ModePerm FileMode = 0777 // Unix permission bits 权限位.
)

简单些文件第一种方式

package main

import (
	"io/ioutil"
	"log"
)

func main() {
	err := ioutil.WriteFile("demo2.txt",[]byte("hello golang"), 0666)
	if err != nil {
		log.Fatal(err)
	}
}

简单写文件第二种方式

package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	file, err := os.OpenFile("demo.txt", os.O_CREATE, 0666)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	n, err := io.WriteString(file, "hello world")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("写了%d个字节\n", n)
}

日志 log


错误 errors

待更新


序列化&反序列化

json

yaml

xml


反射 reflect

获取变量的类型

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var a int64 = 21
	demo(a)

	var b float32 = 3.85
	demo(b)

	var c int32
	demo(c)
}

func demo(x interface{}) {
	t := reflect.TypeOf(x)
	fmt.Println(t.Kind())

	switch t.Kind() {
	case reflect.Int32:
		fmt.Println("type is int32")
	case reflect.Int64:
		fmt.Println("type is int64")
	case reflect.Float32:
		fmt.Println("type is float32")
	case reflect.Float64:
		fmt.Println("type is float64")
	default:
		fmt.Println("is other type")
	}
}

获取变量的值并修改

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var a int64 = 21
	demo(&a)
	fmt.Println("a=", a)
}

func demo(x interface{}) {
	v := reflect.ValueOf(x)
	fmt.Println(v.Kind())

	switch v.Kind() {
	case reflect.Int32:
		fmt.Println("value is int32", v.Int())
	case reflect.Int64:
		v.SetInt(28)
		fmt.Println("value is int64", v.Int())
	case reflect.Float32:
		fmt.Println("value is float32", v.Float())
	case reflect.Float64:
		fmt.Println("values is float64", v.Float())
	case reflect.Ptr:
		v.Elem().SetInt(999)
	default:
		fmt.Println("is other type value")
	}
}

结构体反射

获取结构体类型

package main

import (
	"fmt"
	"reflect"
)

type Server struct {
	Host string
	Port int
	Username string
	Password string
}

func main() {
	var s Server
	s.Host = "127.0.0.1"
	s.Port = 3306
	s.Username = "root"
	s.Password = "111111"

	v := reflect.ValueOf(s)

	fmt.Println(v.NumField())
	for i:=0;i<v.NumField();i++{
		f := v.Field(i)
		fmt.Println(f.Type(), f.Type().Name(), f.Interface())
	}
}

设置结构体的值

package main

import (
	"fmt"
	"reflect"
)

type Server struct {
	Host string
	Port int
	Username string
	Password string
}

func main() {
	var s Server
	s.Host = "127.0.0.1"
	s.Port = 3306
	s.Username = "root"
	s.Password = "111111"

	v := reflect.ValueOf(&s)
	v.Elem().Field(0).SetString("192.168.1.1")
	v.Elem().Field(1).SetInt(9980)

	v.Elem().FieldByName("Username").SetString("admin")
	v.Elem().FieldByName("Password").SetString("888888")

	fmt.Println(s)
}

获取结构体的方法

package main

import (
	"fmt"
	"reflect"
)

type Persion struct {
	Name string
	Age int
}

func (s *Persion) Eat() {
	fmt.Println(s.Name, "eat...")
}

func (s *Persion) Sleep() {
	fmt.Println(s.Name, "sleep...")
}

func main() {
	var p Persion

	// 如果方法的接收者是指针类型,那么传参数要传变量的指针才可以
	v := reflect.ValueOf(&p)
	t := v.Type()

	fmt.Println("method count:", v.NumMethod())
	for i:=0; i<v.NumMethod(); i++{
		method := t.Method(i)
		fmt.Println(method.Type, method.Name, method.Func, method.Index, method.PkgPath)
	}
}

调用结构体的方法

package main

import (
	"fmt"
	"reflect"
)

type Persion struct {
	Name string
	Age int
}

func (s *Persion) Eat() {
	fmt.Println(s.Name, "eat...")
}

func (s *Persion) Sleep() {
	fmt.Println(s.Name, "sleep...")
}

func (s *Persion) Test(name string, age int) {
	fmt.Printf("name is %s, age is %d\n", name, age)
}

func main() {
	var p Persion

	// 如果方法的接收者是指针类型,那么传参数要传变量的指针才可以
	v := reflect.ValueOf(&p)

	var value []reflect.Value
	value = append(value, reflect.ValueOf("王哈哈"))
	value = append(value, reflect.ValueOf(25))

	v.MethodByName("Test").Call(value)
}

获取结构体的Tag信息

指针传递

package main

import (
	"fmt"
	"reflect"
)

type Server struct {
	Host string `json:"host" data:"host"`
	Port int `json:"port" data:"port"`
}

func main() {
	var s Server
	v := reflect.ValueOf(&s)
	t := v.Type()

	for i:=0;i<t.Elem().NumField();i++ {
		json := t.Elem().Field(i).Tag.Get("json")
		data := t.Elem().Field(i).Tag.Get("data")
		fmt.Printf("json: %v, data:%v\n", json, data)
	}
}

or

值传递

package main

import (
	"fmt"
	"reflect"
)

type Server struct {
	Host string `json:"host" data:"host"`
	Port int `json:"port" data:"port"`
}

func main() {
	var s Server
	v := reflect.ValueOf(s)
	t := v.Type()

	for i:=0;i<t.NumField();i++ {
		json := t.Field(i).Tag.Get("json")
		data := t.Field(i).Tag.Get("data")
		fmt.Printf("json: %v, data:%v\n", json, data)
	}
}

总结

通过反射我们可以拿到变量和结构体的类型信息和值信息,可以动态修改变量的值和结构体的值,对于结构体而言可以调用结构体的方法,还可以获取结构体的Tag信息。

反射应用场景

通过反射我们可以使用在文件解析,ORM映射,反序列化等功能中。


信号

待更新


网络通信

待更新


数据库操作

mysql

redis

mongodb

go-jwt

结构体版

package main

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"log"
	"time"
)


type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

func main() {
	m := MyClaims{
		"wanghaha",
		jwt.StandardClaims{
			NotBefore: time.Now().Unix(),
			ExpiresAt: time.Now().Unix() + 60*60*3, // 3小时后过期
			Issuer: "wanghaha",
		},
	}

	mySigningKey := []byte("AllYourBase")
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, m)
	tokenString, err := t.SignedString(mySigningKey)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(tokenString)


	// parse
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})
	if err != nil {
		fmt.Println(jwt.ValidationErrorExpired)

		fmt.Println(err.Error())
		log.Fatal(err)
	}

	// 这里去解析就好了
	fmt.Println(token.Claims)
	fmt.Println(token.Claims.(*MyClaims).Username)
}

map版

package main

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"log"
	"time"
)


func main() {
	mySigningKey := []byte("AllYourBase")
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"exp": time.Now().Unix() + 60*60*3,
		"iss": "wanghaha",
		"nbf": time.Now(),
	})

	tokenString, err := t.SignedString(mySigningKey)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(tokenString)


	// parse
	token, err := jwt.ParseWithClaims(tokenString, jwt.MapClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})
	if err != nil {
		fmt.Println(jwt.ValidationErrorExpired)

		fmt.Println(err.Error())
		log.Fatal(err)
	}

	// 这里去解析就好了
	fmt.Println(token)
	fmt.Println(token.Claims.(jwt.MapClaims)["exp"])
	fmt.Println(token.Claims.(jwt.MapClaims)["iss"])
}