golang 学习笔记

配置go环境

  1. 解压go包
  2. 配置GOPATH
  3. 如果需要下载包 golang.org/x/net/context --> github.com/golang/net/context

goland(IDE)快捷操作

功能操作
删除当前行⌘⌫
行注释⌘/
块注释⌥⌘/
函数使用提示⌘P
代码检查并提供快速修复⌥⏎

导入包

集合导入包数据

import(
    "fmt"
    "math/rand"
    …… ……
)
包名介绍作用
fmt基本包用于输入输出
math数学基本包
表内容表内容代码内容

函数

函数名作用
fmt.Println(String)输出指定字符串

函数指定返回值

func 函数名(参数1,参数2 数据类型) (返回数据1,返回数据2 数据类型){
    …… ……
    return
}

# example
func add(x , y int) (y , x) {
	return 
}

函数值指定返回数据类型

func 函数名(参数1,参数2 数据类型) (返回数据1的类型,返回数据2的类型){
    …… ……
    return 返回数据1 , 返回数据2
}

# example
func add(x , y int) (int , int) {
	return x + y , x
}

函数返回值类型可以是func函数。
在函数中修改变量一般不影响全局的值,所以如果要改,必须传递一个指针进来,这个和C++相同
如果只返回一个返回数据,可以不写括号func 函数名(参数1,参数2 数据类型) 返回数据类型{……}

闭包

一个函数的返回值是一个函数。

原理:函数中回调一个子函数,可以理解为匿名函数,因为父函数被子函数依赖,所以其函数中定义的变量会一直存在内存中,每次调用函数后产生变化都是存在的。

可以把闭包理解为一个封装的环境中执行某个函数,每次定义一个变量存储这个环境,每次使用这个变量就是执行这个闭包中的子函数。

所以一般父函数中做的是环境定义,子函数做的是操作执行,如果定义两个变量,这两个变量中的值是相互不影响的。

对于执行的理解,可以是 f := function() 理解为执行父函数, f() 理解为执行子函数

func 函数名() func(参数类型) 返回值类型{
    相关操作1
    return func(参数 参数类型) 返回值类型{
        相关操作2
        return 返回值
    }
}

# example
func function() func() {
    a := 1
    fmt.Println("只有第一次执行函数的时候才会触发")
    return func(){
        a ++
        fmt.Println("每次执行这个函数都会执行,并且a变量值会一直存在")
    }
}

# 定义一个变量存储这个函数
f := function()
f()     // 这就是执行一次闭包

闭包可以有值输入或输出

func function() func(int) int{
    a := 1
    fmt.Println("只有第一次执行函数的时候才会触发")
    return func(x int) int{
        a += x
        fmt.Println("每次执行这个函数吧输入的数加入")
        return a
    }
}

# 定义一个变量存储这个函数
f := function()
f(12)     // 这就是执行一次闭包

变量

定义的所有变量都要被使用 ,否则会报错

变量类型设定

变量名1 变量类型1 , 变量名2 变量类型2

# 当变量类型相同的时候,等同如下
变量名1 , 变量名2 变量类型

# example
x int , y int    <====>    x , y int

定义变量

var 变量名1 , 变量名2 变量类型

# example
var x , y bool

变量初始化赋值

var 变量名1 , 变量名2 变量类型 = 值1 , 值2

# 系统自动获取变量类型
var 变量名1 , 变量名2 = 值1 , 值2

# example
var x , y int = 1 , 2
var x , y = 1 , 2
var (
    x = 1
    y = 2
)

下面是简洁写法,但是不能在函数外使用

变量1 , 变量2 := 值1 , 值2

# example
x , y := 1 , 2

变量类型

变量类型含义默认值代表符号
bool代表ture 或者 falsefalse%t
string代表字符串(空)%s
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr整数类型0
byteuint8 的别名0%d
runeint320%d
float32 float64浮点数0%f
complex64 complex128虚数(0+0i)

特殊运算

<< 所有二进制数向左移动n位
>> 所有二进制数向右移动n位

类型装换

表达式 T(v) 将值 v 转换为类型 T

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)


#string到int
int,err:=strconv.Atoi(string)
#string到int64
int64, err := strconv.ParseInt(string, 10, 64)
#int到string
string:=strconv.Itoa(int)
#int64到string
string:=strconv.FormatInt(int64,10)

获取变量

test string
flag.StringVar(&test, "外部调用的名字", "默认值", "help提示文字")
flag.Parse()
// 然后test变量就会通过外部获取值

解决没有输入参数的异常

	if mip == "Error" || cip == "Error" || vip == "Error" {
		flag.Usage()
		return
	}

常量定义

const 常量1 , 常量2 = 值1 , 值2

# 可以大批量复制

循环

基本for循环(同C++的for)

for i := 初始值 ; i < 最大值 ; i ++ {
    …………
}

初始值和数据变化模块可以不写(同C++的while)

for i < 值 {
}

死循环

for {
}

用range和数组相结合

会遍历整个数组中所有元素,然后每次都会把一个数据给变量2,而变量1会每次+1

for 变脸1,变量2 := range 数组名{
    …… ……
}

变量1用来记录需要,可以不写

判断

if 判断语句 {
} else {
}

判断语句中可以有变量定义,例如:

if err:=test();err != nil {
} else {
}

switch - case

switch i {
case "值1":
    ……
case 函数名():
    ……    
defalut:
    ……
}

延迟函数

最后执行下面这个函数,多个defer的时候,是采用堆栈逻辑,原理是先进后出执行

defer 函数()

指针

其零值是 nil

*类型 指代某类型的指针

# example
var i *int

那么 i 的值就是 nil ;
在不赋值去情况下使用 *i 会报告异常

结构体

可以理解为一个自定义的数据类型

type 结构体名 struct{
    变量1 类型
    变量2 类型
}

# 使用方法
结构体.变量

结构体指针

结构体变量 := 结构体{值1,值2……}
指针名 := &结构体变量

# example
a := add{1,2}
b := &a
b.x 的值就是1

go没有类的说法,但是可以就结构体进行函数方法的定义

语法累死于闭包,函数的返回值是一个函数。

func (结构体变量 结构体类型) 方法名()  返回值类型{
    return 指定类型的值
}

结构体变量 := 结构体…………
结构体变量.方法名()

# example
type Vertex struct {
	X int
	Y int
}

func (v *Vertex) Abs() float64 {
	sum := v.X * v.X + v.Y * v.Y
	return math.Sqrt(float64(sum))
}

func main()  {
	v := Vertex{4,3}
	fmt.Println(v.Abs())
}

不光可以对自定义的结构体进行定义,也可以对数据类型,但是需要修改一个名字

type Vertex float

func (v Vertex) Abs() float64 {
	return math.Sqrt(float64(v))
}

接口

接口类型是由一组方法定义的集合。 接口类型的值可以存放实现这些方法的任何值。
但是不需要完成接口内方法的具体内容。

type 接口名 interface{
    方法名() 方法返回值
}

数组 slice

其空值为 nil

# 基本格式
数组名 []数据类型

# make创建一个数组格式
数组名 := make([]数据类型 , len初始值 , cap初始值)

# 新添加元素
数组名 = append(数组名,值1,值2)

len默认值是0 , cap默认值是0

切片相关概念

len代表slice实际元素的个数;
cap代表当前slice的容量

当len的长度不足够的时候,可以直接把数据存到容量中,如果达到初始设定容量,就会添加新加一个不比初始容量小的新容量,添加的容量无上限。

  1. 原则:cap>=len
  2. cap一定是偶数
  3. cap要么和初始cap相同,要么是>=(cap初始值*2)

键名映射

一般和make连用,这个不要求有数据

数组名 = make(map[键名类型]数组类型)

# 赋值的时候
数组名[任意键名] = 满足数组类型值

主要作用就是让数组的键名(下标),可以被自定义

如果有数据

 数组名 = map[键名类型]数组类型{
     键名1 : {值1 , 值2}
     键名2 : {值1 , 值2}
}

删除某键名的元素

delete(数组,键名)

查看某键名的元素是否存在

变量名 , 存储状态变量 := 数组名[键名]
变量名 , 存储状态变量 = 数组名[键名]

异常处理

if err := buildMha() ; err != nil {
    // 程序继续,中断函数
	log.Panic(err)

	// 直接切断程序
	log.Fatal(err)
}

写文件

覆盖写

    err := ioutil.WriteFile("test.txt", []byte("Hi\n"), 0666)
    if err != nil {
        log.Fatal(err)
    }

追加写

func myWrite(config string, word ...string) error {
	for _, i := range word {
		f, err := os.OpenFile(config, os.O_WRONLY, 0644)
		if err != nil {
			fmt.Println("cacheFileList.yml file create failed. err: " + err.Error())
			return errors.New(i)
		} else {
			// 查找文件末尾的偏移量
			n, _ := f.Seek(0, os.SEEK_END)
			// 从末尾的偏移量开始写入内容
			_, err = f.WriteAt([]byte(i+"\n"), n)
		}
		_ = f.Close()

		if err != nil {
			fmt.Println("cacheFileList.yml file writed failed. err: " + err.Error())
			return errors.New(i)
		}
	}
	return nil
}

Linux

ssh连接服务器

func connect(user, password, host, key string, port int, cipherList []string) (*ssh.Session, error) {
	var (
		auth         []ssh.AuthMethod
		addr         string
		clientConfig *ssh.ClientConfig
		client       *ssh.Client
		config       ssh.Config
		session      *ssh.Session
		err          error
	)
	// get auth method , 用秘钥或者密码连接
	auth = make([]ssh.AuthMethod, 0)
	if key == "" {
		auth = append(auth, ssh.Password(password))
	} else {
		pemBytes, err := ioutil.ReadFile(key)
		if err != nil {
			return nil, err
		}

		var signer ssh.Signer
		if password == "" {
			signer, err = ssh.ParsePrivateKey(pemBytes)
		} else {
			signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(password))
		}
		if err != nil {
			return nil, err
		}
		auth = append(auth, ssh.PublicKeys(signer))
	}

	if len(cipherList) == 0 {
		config = ssh.Config{
			Ciphers: []string{"aes128-ctr", "aes192-ctr",
				"aes256-ctr", "aes128-gcm@openssh.com", "arcfour256",
				"arcfour128", "aes128-cbc", "3des-cbc", "aes192-cbc", "aes256-cbc"},
		}
	} else {
		config = ssh.Config{
			Ciphers: cipherList,
		}
	}

	clientConfig = &ssh.ClientConfig{
		User:    user,
		Auth:    auth,
		Timeout: 30 * time.Second,
		Config:  config,
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
	}

	// ssh 连接
	addr = fmt.Sprintf("%s:%d", host, port)

	if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
		return nil, err
	}

	// create session
	if session, err = client.NewSession(); err != nil {
		return nil, err
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}

	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		return nil, err
	}

	return session, nil
}
const (
	username = "root"
	password = ""
	key      = "/root/.ssh/id_rsa"
	port     = 22
)

func sshDoShell(ip string, cmd string) error{
	ciphers := []string{}
	session, err := connect(username, password, ip, key, port, ciphers)

	if err != nil {
		fmt.Println("连接 ", ip, " 异常")
		log.Fatal(err)
	}
	
	defer func() {
		if err := session.Close(); err != nil {
			// log etc
		}
	}()

	session.Stdout = os.Stdout
	session.Stderr = os.Stderr

	err = session.Run(cmd)
	if err != nil{
		return errors.New(err.Error())
	}

	return nil
}

执行shell命令

func myCmd(bash string, shell ...string) error {
	contentArray := make([]string, 0, 5)
	cmd := exec.Command(bash, shell...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(cmd.Stderr, "error=>", err.Error())
	}

	_ = cmd.Start()

	reader := bufio.NewReader(stdout)

	contentArray = contentArray[0:0]
	var index int
	//实时循环读取输出流中的一行内容
	for {
		line, err2 := reader.ReadString('\n')
		if err2 != nil || io.EOF == err2 {
			break
		}
		fmt.Print(line)
		index++
		contentArray = append(contentArray, line)
	}
	err = cmd.Wait()

	if err != nil {
		fmt.Printf("Execute Shell %s: ", shell)
		return errors.New("failed with error:"+err.Error())
	}

	return nil
}

基于http协议的API接口实现

var ListenSig  = make(chan int) 

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

// 记录访问记录
func Logger(inner http.Handler, name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		inner.ServeHTTP(w, r)

		File.WriteAccessLog(r.Method+"\t"+r.RequestURI+"\t"+name+"\t"+time.Since(start).String())
	})
}

// 书写路由信息
func NewRouter() *mux.Router {
	router := mux.NewRouter().StrictSlash(true)
	for _, route := range routes {
		var handler http.Handler
		handler = route.HandlerFunc
		handler = Logger(handler, route.Name)
		router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(handler)
	}

	return router
}

var routes = Routes{
	// 获取指定日期的监控信息
	Route{
		"GetInfo",
		"GET",
		"/monitor/info",
		ReturnMonitorInfo,
	},

	// 收集监控数据并保存处理
	Route{
		"MonitorCollect",
		"POST",
		"/monitor/collect",
		PostMonitorInfo,
	},
}

// 具体接口触发函数
func PostMonitorInfo(w http.ResponseWriter, r *http.Request) {

}

func ReturnMonitorInfo(w http.ResponseWriter, r *http.Request) {

}

// 启动api接口,port参数为暴露端口
func StartApi(port string) {
	router := NewRouter()
	File.WriteErrorLog(http.ListenAndServe(":"+port, router).Error())
	ListenSig <- 0
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值