go cli脚手架开发利器——cobra库的初体验

2023-11-16

关于

×错例:

  1. 不能完全代替shell,cobra能支持的脚本格式比较局限

  2. 无法像Java -jar -Dxx=str1 -Dxx2=str2 那样读取-D指示的值

  3. 读取参数只能为无格式纯文本,不要尝试读取json、特殊字符、转义符和富文本。

  4. 避免一大堆可变配置参数都通过flag传,参数太多建议改成读取配置文件

√正确:

  1. 读取5个以上的flag时使用,配置文件+viper,环境变量等,减少flag的个数到5个以内;

  2. 参数的值不要过长,仅纯文本string、int和bool类型,富文本、json等建议通过flag传文件路径,在run方法的逻辑读取文件,进行操作

  3. 短平快、小型脚手架推荐使用cobra封装命令集,同时学习了解pflag、flag、viper库

说明

cobra 简介

cobra既是一个用于创建强大现代CLI应用程序的库,也是一个生成应用程序和命令文件的程序。cobra被用在很多go语言的项目中,比如 Kubernetes、Docker、Istio、ETCD、Hugo、Github CLI等等,更多项目详见此列表。

cobra 概念

cobra由命令、参数、标志组成
commands代表动作,args是事物,flags是动作的修饰符(一般两个-连接符)
模式如下:
APPNAME VERB NOUN --ADJECTIVE. or APPNAME COMMAND ARG --FLAG(APPNAME 动词 名词 形容词 或者 APPNAME 命令 参数 标志)
如下的例子,server 是command,port是flag

hugo server --port=1313

Commands

命令是交互程序的中心,每一个命令都有子命令。
链接:cobra package - github.com/spf13/cobra - Go Packages
需要rootCmd和其他命令(按需)

Flags

flag是一种修改命令行为的方式,cobra支持完全兼容POSIX标志,也支持go flag package,cobra可以定义到子命令上的标志,也可以仅对该命令可用的标志

Args

args参数是命令command需要识别的一些值,cobra可以指定读取任意数量的参数,也可以不接受参数,此时该输入会被当作未定义的command报错。
command、args搭配使用

教程正文

demo1 快速了解

参考:Go语言命令行利器cobra使用教程 - 简书

demo

main.go负责调用rootCmd execute方法

import "cobra_cmd/cmd"

func main() {
    cmd.Execute()
}

在cmd目录下创建rootcmd.go

//每一个command命令,都是一个 &cobra.Command{
} 示例
var rootCmd = &cobra.Command{
    Use:   "root-cli",
    Short: "示例脚本 root cli",
    Long:  `这是 cobra 测试程序使用的示例脚本,您可参考cobra其他文档并随时更新本demo`,
         //参数验证器,设置某个脚本
能接受参数的个数。
    Args:  cobra.MinimumNArgs(1),
    RunE:  runRoot, //RunE Run字段都是执行具体的函数
,抽到别处定义
}
//rootCmd.Execute() 是命令执行入口
func Execute() {
    if err := rootCmd.Execute(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
//具体的执行逻辑
func runRoot(cmd *cobra.Command, args []string) error {
    fmt.Printf("execute %s args:%v \n", cmd.Name(), args)
        //例如 这里处理无参数启动时程序处理
        if len(args) < 1 {
          return errors.New("requires at least one arg")
        }
     // do something.

    return nil

}

var cmdPrint = &cobra.Command{
    Use:   "print [string to print]",
    Short: "Print anything to the screen",
    Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Print: " + strings.Join(args, " "))
    },
}

var cmdEcho = &cobra.Command{
    Use:   "echo [string to echo]",
    Short: "Echo anything to the screen",
    Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Print: " + strings.Join(args, " "))
    },
}

var cmdTimes = &cobra.Command{
    Use:   "times [# times] [string to echo]",
    Short: "Echo anything to the screen more times",
    Long: `echo things multiple times back to the user by providing
a count and a string.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        for i := 0; i < echoTimes; i++ {
            fmt.Println("Echo: " + strings.Join(args, " "))
        }
    },
}

 //定义 标志
var echoTimes int

func init() {
    //通过AddCommand组成父子关系,多级命令
    rootCmd.AddCommand(helloCmd)

    // root有两个子命令,和一个cmdEcho命令下的子命令cmdTimes
    //一级root --> 二级print,echo --> 三级times
    rootCmd.AddCommand(cmdPrint, cmdEcho)
    cmdEcho.AddCommand(cmdTimes)

    //本地标志,只在mdTimes命令

起作用
    cmdTimes.Flags().IntVarP(&echoTimes, "echoTimes", "t", 1, "times to echo the input")
}

以上是一个入门demo,演示了命令command结构、标志的定义和读取、命令组成上下级、父子关系。

重点:
1.rootCmd和其他command放 cmd 包下;
2.在单独的commandXxx.go文件里,为每一个command定义 &cobra.Command{} 结构体并在init()方法里通过AddCommand() 做父子上下级关系关联、以及flag标志的读取操作;
3.main()入口方法调用到rootCmd.Execute()即完成工作。

知识点:Command创建命令

结构如下,列举大概常用的字段:

&cobra.Command{
        //
命令名称
    Use:   "echo [string to echo]",
        //
命令别名
    Aliases: []string{"log","output"},
        //
命令简介
    Short: "Echo anything to the screen",
        //
命令详细说明
    Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Print: " + strings.Join(args, " "))
    },
}
  • use 是该命令的用法,单行用法消息,表示了某一级命令,可以理解为该命令的名字;
  • Short、Long是该命令的一行简介、一大段详细介绍文本;具体会在输出help帮助时才有不一样的提示,可以粗暴设置成同样内容;
  • Run、RunE是命令被执行时的具体逻辑,RunE会返回error给上层;
  • Alias是一组可代替Use那个名字的,同名,都会映射到本命令;
  • Args:参数验证,可以限制参数的个数等等,有如图几种验证方法:
    在这里插入图片描述

demo2 使用参数验证器、钩子函数

demo

package main

import (
    "bufio"
    "fmt"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
    "os"
)

var rootCmd = &cobra.Command{
    Use:   "demo",
    Short: "A brief description of your application",
    Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
    //运行命令的逻辑
    //Run: func(cmd *cobra.Command, args []string) {
    //debug
    //fmt.Println("== root命令运行成功 ==")

    //},

}

// 再定义二级子命令:
var createCmd = &cobra.Command{
    Use:   "create",
    Short: "创建书签",
}

var urlCmd = &cobra.Command{
    Use:   "url",
    Short: "Bookmark a url link ",
    Long:  "收藏一个url链接",

    //cobra 常用的参数配置校验器如下:
    //
    //MinimumNArgs(int) 当参数数目低于配置的最小参数个数时报错
    //MaximumNArgs(int) 当参数数目大于配置的最大参数个数时报错
    //ExactArgs(int)    如果参数数目不是配置的参数个数时报错
    //NoArgs            没有参数则报错

    //参数验证除了RangeArgs 还有 NoArg、ExactArgs、
    Args: cobra.RangeArgs(1, 3),

    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("link is:", link)
        if len(args) == 2 {
            fmt.Println(args[0], args[1])
        } else if len(args) == 0 {
            fmt.Println("收藏链接参数:", args)
            return
        } else {
            fmt.Println("收藏链接参数:", args)
        }
        file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
        if err != nil {
            fmt.Println(err)
        }
        //及时关闭file句柄
        defer file.Close()
        //写入文件时,使用带缓存的 *Writer
        write := bufio.NewWriter(file)
        for i := 0; i < 5; i++ {
            write.WriteString("link \n")
        }
        //Flush将缓存的文件真正写入到文件中
        write.Flush()
    },

}
var link string
var filePath string

// init 方法完成父子关系绑定,标志的初始化设置以及其他初始化工作
func init() {
    rootCmd.AddCommand(createCmd)
    createCmd.AddCommand(urlCmd)
    //持久标志,传递给所有子命令
    rootCmd.PersistentFlags().StringVarP(&filePath, "path", "p", "./bookmarks.txt", "save to txt file")
    //局部标志,仅用于具体一个子命令
    urlCmd.Flags().StringVarP(&link, "link", "l", "", "收藏链接格式: 链接地址 名称")

    //钩子函数演示
    rootCmd.AddCommand(hookCmd)
    hookCmd.AddCommand(hookSub)
    hookSub.AddCommand(hookfinal)

}
func main() {

    // For environment variables.
    viper.SetEnvPrefix("core")
    viper.AutomaticEnv()
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

}

// / 钩子函数测试
var hookCmd = &cobra.Command{
    Use:   "hookroot",
    Short: "钩子函数测试 一级",
    Long:  "测试 生命周期的不同钩子函数的继承关系",
    PersistentPreRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookroot: PersistentPreRun")
    },
    PreRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookroot: PreRun")
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookroot: Running...")
    },
    PostRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookroot: PostRun")
    },
    PersistentPostRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookroot: PersistentPostRun")
    },
}

// // 会继承 父命令的PersistentPreRun、PersistentPostRun
var hookSub = &cobra.Command{
    Use:   "hooksub",
    Short: "钩子函数测试 二级",
    PreRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hooksub: PreRun")
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("hooksub: Running...")
    },
    PersistentPostRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hooksub: PersistentPostRun") //覆盖了root的PersistentPostRun,并传给下级
    },
}

// // 会继承 父命令的PersistentPreRun、PersistentPostRun
var hookfinal = &cobra.Command{
    Use:     "hookfinal",
    Aliases: []string{"final", "finally"},
    Short:   "钩子函数测试 三级",
    PreRun: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookfinal: PreRun")
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("hookfinal: Running...")
    },
}

output:
//go run .\helloworld.go hookroot hooksub hookfinal
//hookroot: PersistentPreRun
//hookfinal: PreRun
//hookfinal: Running...
//hooksub: PersistentPostRun/

以上是一个进阶demo,演示了PersistentFlags和Flags的区别,以及钩子函数在向下传递时可被覆盖

重点:
1.PersistentFlags 设置的是持久标志,由rootCmd根命令设置,可被其他命令使用,而flag设置的只能在当前命令使用;
2.在单独的command执行之前、之后都可以执行其他操作,也即预先处理、后置处理。执行顺序为PersistentPreRun、PreRun、Run、PostRun、PersistentPostRun
3.带Persistent的可以传递给子命令(继承),但也可以被子命令重新声明而被覆盖(重写)
4.不带Persistent开头的前后处理

知识点:参数验证方法

以下代码:Args: cobra.MinimumNArgs(1)就是一个验证方法

import (
  "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
  Use:   "myapp",
  Short: "A brief description of your application",
  Long:  `A longer description that spans multiple lines and likely contains examples and usage of using your application.`,
  Args: cobra.MinimumNArgs(1),
  Run: func(cmd *cobra.Command, args []string) {
    // Do something here
  },
}

func init() {
  // Here you will define your flags and configuration settings.
}

func Execute() {
  if err := rootCmd.Execute(); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
}
 

可以看到在 rootCmd 中设置了 Args: cobra.MinimumNArgs(1),这将强制要求至少传入一个参数,否则会抛出一个错误。此外,还可以使用 cobra 提供的其他参数验证方法,例如:

cobra.MaximumNArgs(n int):强制要求不超过 n 个参数。
cobra.OnlyValidArgs([]string):强制要求传入的参数必须是所指定的 string 类型的 slice 中的值。
cobra.ArgRange(min, max int):强制要求传入参数的数量在 min 和 max 之间。
以上是一些常用的参数验证方法,Cobra 还有更多的验证方法和选项,可以根据实际需求进行选择和设置。

知识点:生命周期钩子函数

参考:
Go 每日一库之 cobra - 知乎
Cobra 中文文档 - 掘金

可以在执行命令之前和之后运行一个函数。PersistentPreRun 和 PreRun 函数将在 Run 之前执行。PersistentPostRun 和 PostRun 会在 Run 之后运行。如果子级未声明自己的 Persistent * Run 函数,则子级将继承父级的。这些函数的执行顺续如下:

PersistentPreRun
PreRun
Run
PostRun
PersistentPostRun
PersistentXxx是可以被子命令继承的前、后置处理

知识点:帮助命令

当你添加了子命令,Cobra 会自动添加一些帮助命令。当你执行 app help 命令时会显示帮助信息。另外,help 还支持其他命令作为输入参数。举例来说,你有一个没有额外配置的 create 命令,app help create 是有效的。每一个命令还会自动获取一个 --help 标志。

help 就像其他命令一样。并没有特殊的逻辑或行为。实际上,你可以根据需要提供自己的服务。
定义你自己的 help
你可以使用下面的方法提供你自己的 Help 命令或模板。

cmd.SetHelpCommand(cmd *Command)
cmd.setHelpCommand(f func(*Command, []string))
cmd.setHelpTemplate(s string)

后两者也适用于所有子命令。

知识点:使用信息

当用户提供无效的标志或无效的命令时,Cobra 会通过向用户显示 usage 进行响应。
这时可以自定义usage用法,提供自己的 usage函数和模板

cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)

可以参考 GitHub CLI 项目中usage使用信息的写法。

demo3 生成帮助文档文件(markdown文件)

参考cobra document#mrkdown-docs
cobra支持生成所有命令的帮助文档树doc.GenMarkdownTree(cmd,dir)

demo

main.go:

import (
	"github.com/spf13/cobra/doc"
	"log"
	"os"
)

func InitCommand() {
	rootCmd.AddCommand(helloCmd)
	// 两个顶层的命令,和一个cmdEcho命令下的子命令cmdTimes
	rootCmd.AddCommand(cmdPrint, cmdEcho)
	cmdEcho.AddCommand(cmdTimes)
	//utils.Mkdir("./docs")
	os.MkdirAll("H:\\docs", os.ModePerm) //显式创建目标文件夹,文件夹存在时再次调用不会做任何事情
	err := doc.GenMarkdownTree(rootCmd, "H:\\docs") //核心api  GenMarkdownTree
	if err != nil {
		log.Fatal(err)
	}
}

知识点 生成帮助文档文件(markdown文件)

给某个命令及其子命令生成帮助文档树(一系列文档),参考以下代码片段:

err := doc.GenMarkdownTree(rootCmd, "H:\\docs") //核心api  GenMarkdownTree
	if err != nil {
		log.Fatal(err)
	}

即可在目标文件夹下看到生成的md文件:
在这里插入图片描述

其他高级用法或生成其他格式帮助文档,请参考cobra document#mrkdown-docs ,以及cobra代码库的github.com/spf13/cobra/doc文件夹下的代码和文档。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go cli脚手架开发利器——cobra库的初体验 的相关文章

  • 【计算机毕业设计】趵突泉景区的智慧导游小程序_5ztvv

    当今社会已经步入了科学技术进步和经济社会快速发展的新时期 国际信息和学术交流也不断加强 计算机技术对经济社会发展和人民生活改善的影响也日益突出 人类的生存和思考方式也产生了变化 传统趵突泉景区的智慧导游采取了人工的管理方法 但这种管理方法存
  • 【计算机毕业设计】SpringBoot+Vue.js协同过滤算法美食推荐小程序 _7tr93

    伴随着我国社会的发展 人民生活质量日益提高 于是对各种需求进行规范而严格是十分有必要的 所以许许多多的微信小程序应运而生 此时单靠人力应对这些事务就显得有些力不从心了 所以本论文将设计一套协同过滤算法美食推荐小程序 帮助美食推荐进行美食分类
  • 【C++】__declspec含义

    目录 一 declspec dllexport 如果这篇文章对你有所帮助 渴望获得你的一个点赞 一 declspec dllexport declspec dllexport 是 Microsoft Visual C 编译器提供的一个扩展
  • qt.qpa.plugin: Could not find the Qt platform plugin “windows“ in ““

    系统环境 Win10家庭中文版 Qt 5 12 9 链接了一些64位的第三方库 程序编译完运行后出现 qt qpa plugin Could not find the Qt platform plugin windows in 弹窗如下 网
  • Android Navigation的四大要点你都知道吗?

    在JetPack中有一个组件是Navigation 顾名思义它是一个页面导航组件 相对于其他的第三方导航 不同的是它是专门为Fragment的页面管理所设计的 它对于单个Activity的App来说非常有用 因为以一个Activity为架构
  • 一台java服务器可以跑多少个线程?

    一台java服务器可以跑多少个线程 一台java服务器能跑多少个线程 这个问题来自一次线上报警如下图 超过了我们的配置阈值 打出jstack文件 通过IBM Thread and Monitor Dump Analyzer for Java
  • Hutool改变我们的coding方式(二)

    Hutool改变我们的coding方式 Hutool 简介 Hutool如何改变我们的coding方式 文档 安装 Maven
  • 史上最全Java面试八股文(带全部答案)2024年最新版

    今天要谈的主题是关于求职 求职是在每个技术人员的生涯中都要经历多次 对于我们大部分人而言 在进入自己心仪的公司之前少不了准备工作 有一份全面细致 面试题 将帮助我们减少许多麻烦 在跳槽季来临之前 特地做这个系列的文章 一方面帮助自己巩固下基
  • 计算机Java项目|在线图书管理

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|电影购票系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • APP开发毕业设计|ssm爱心小屋公益机构智慧管理APP

    作者主页 编程指南针 作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智
  • 2024史上最全Java面试八股文(带全部答案)

    今天要谈的主题是关于求职 求职是在每个技术人员的生涯中都要经历多次 对于我们大部分人而言 在进入自己心仪的公司之前少不了准备工作 有一份全面细致 面试题 将帮助我们减少许多麻烦 在跳槽季来临之前 特地做这个系列的文章 一方面帮助自己巩固下基
  • 【固定翼飞行器】用于计算固定翼飞机空气动力学的紧凑涡旋格方法研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现
  • 【自适应滤波】一种接近最佳的自适应滤波器,用于突发系统变化研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章
  • 【go语言】AST抽象语法树详解&实践之扫描代码生成错误码文档

    背景 为了能识别出代码中抛出错误码的地址和具体的错误码值 再根据错误码文件获取到错误码的具体值和注释 方便后续的排错 这里使用AST进行语法分析获取到代码中的目标对象 一 编译过程 在开始解析代码之前先补充了解一下编译过程 编译过程是将高级
  • 初学者如何快速入门Python(内附详细攻略),一文讲清

    目前python可以说是一门非常火爆的编程语言 应用范围也非常的广泛 工资也挺高 未来发展也极好 Python究竟应该怎么学呢 我自己最初也是从零基础开始学习Python的 给大家分享Python的学习思路和方法 一味的买书看书 看视频 是
  • 计算机Java项目|有机蔬菜商城

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 【C#】基础巩固

    最近写代码的时候各种灵感勃发 有了灵感 就该实现了 可是 实现起来有些不流畅 总是有这样 那样的卡壳 总结下来发现了几个问题 1 C 基础内容不是特别牢靠 理解的不到位 导致自己想出来了一些内容 但是无法使用正确的C 代码实现 导致灵感无法
  • 如何应对Android面试官-> 玩转 ViewPager 懒加载

    前言 ViewPager 缓存页面与预加载机制 通常我们 ViewPager 在使用的是一般都是结合 Fragment 一起使用 我们先来搭一个简单的使用界面 最终搭建出来的效果如下 简单的 ViewPager Fragment 的实现 比
  • SpringCloud Bus动态刷新全局广播

    文章目录 代码地址 配置项目 配置修改 测试 SpringCloud Bus动态刷新定点通知 代码地址 地址 https github com 13thm study springcloud tree main days11 20Bus 配

随机推荐

  • Sqli-labs 博客目录

    之前学习了一遍 sqli labs 这是巩固复习一遍 代码全部手敲 加深印象 Sqli labs 博客目录 Sqli labs Less01 04 基于错误的sql注入 GET Sqli labs Less05 06 报错型sql盲注 GE
  • 第12章 K8s进阶篇-细粒度权限控制

    12 1 什么是RBAC 负责k8s整个集群控制的 不同人员权限的管控 开发 测试 管理员等 12 2 RBAC配置解析 12 3 RBAC常用配置示例 参考官方文档 使用 RBAC 鉴权 Kubernetes 正常是通过yaml文件创建
  • 替代空格

    include
  • host文件的工作原理及应用

    host文件的工作原理及应用 Hosts文件是一个用于存储计算机网络中节点信息的文件 它可以将主机名映射到相应的IP地址 实现DNS的功能 它可以由计算机的用户进行控制 一 Hosts文件基本介绍 Hosts文件的存储位置在不同的操作系统中
  • java 16进制与字符串互相转

    字符串转换成为16进制 无需Unicode编码 param str return public static String str2HexStr String str char chars 0123456789ABCDEF toCharAr
  • 各种字符串Hash函数比较

    转自 beyond the void 常用的字符串Hash函数还有ELFHash APHash等等 都是十分简单有效的方法 这些函数使用位运算使得每一个字符都对最后的函数值产生影响 另外还有以MD5和SHA1为代表的杂凑函数 这些函数几乎不
  • get和post详解

    Get和post是表单提交数据的两种基本方式 get请求数据通过域名后缀url传送 用户可见 不安全 post请求数据通过在请求报文正文里传输 相对比较安全 get是通过url传递表单值 post通过url看不到表单域的值 get传递的数据
  • OceanBase 4.1解读:我们想给用户一个开箱即用的OceanBase部署运维工具

    欢迎访问 OceanBase 官网获取更多信息 https www oceanbase com 关于作者 肖磊 OceanBase 产品专家 负责 OceanBase 运维管控体系产品规划与设计 包括安装部署工具 OBD OAT 运维管控平
  • 小程序领取微信卡券

    小程序领取微信卡券 获取 access token api ticket singuare等完整版 转载自 感谢这位作者 https www cnblogs com w53064 p 9771232 html 返回主页 啊傑Plus 博客园
  • Java实现,手写二叉树

    一 基本概念 二叉树 每个节点最多有两个子树的结构 满二叉树 除了最后一层没有任何节点外 每一层的所有节点都有两个子节点的二叉树 完全二叉树 结构与满二叉树类似 不同点在于最后一层可以不满 但最后一层的节点必须连续集中再最左边 二叉搜索树
  • Redis高级的相关问题总结

    1 rdb和aof有什么区别 你们在工作中如何使用redis的持久化策略 1 rdb定时对整个内存做快照 aof记录每一次执行的命令 2 rdb两次备份之间会丢失数据 aof取决于刷盘策略 相对比较完整 3 rdb宕机恢复速度快 aof恢复
  • XSL-FO Blocks(块)

    XSL FO 的输出位于块区域中 XSL FO 页面 流以及块 内容 块 会 流 入 页面 中 然后输出到媒介 XSL FO 输出通常被嵌套在
  • 监控神器-普罗米修斯Prometheus的安装

    最近看了些AIOPS的资料 对于里面提及的一个普罗米修斯Prometheus起了兴趣 首先是联想到异形 哈哈 去看了一下 普罗米修斯还真是厉害 而且还是开源的 真是搬砖党的福音 功能 在业务层用作埋点系统 Prometheus支持多种语言
  • 面向对象和面向过程的区别,Java为什么说它性能低

    面向对象相比于面向过程 面向对象的代码延展性更好 拿上面的例子举例如果现在要把存储的对象不是大象了而是狮子 那么很明显 面向过程要的方法要所有大象为狮子 面向对象的方法只要改一下关于这个改动的方法也就是 存储 内容 不仅仅是修改 添加删除等
  • C++:模拟实现string类

    文章目录 Iterator类 capacity类 Element access 类 Modifiers类 String operations类 类外成员函数 头文件总括 本篇主要介绍模拟实现string类 string中有相当多的内容 这里
  • AIX6.1 源码编译方式安装 zabbix3.4 代理

    1 aix机器上创建zabbix用户 mkuser zabbix 2 上传zabbix 3 4 11 targz 3 解压 gunzip zabbix 3 4 11 tar gz tar xvf zabbix 3 4 11 tar 4 安装
  • C语言实现DFT计算

    文章目录 一 DFT计算公式 二 DFT程序实现 一 DFT计算公式 这里就不对DFT概念进行叙述 直接上计算公式 其中N为DFT点数 公式如此 但是在程序中并非如此运算 而是利用欧拉公式对DFT的计算公式进行了转化 转换后公式变为 利用转
  • 为什么在控制台输入var name = Symbol();会报错?VM3436:1 Uncaught TypeError: Cannot convert a Symbol value to a str

    问题复现 var name Symbol VM3436 1 Uncaught TypeError Cannot convert a Symbol value to a string 解释每一个部分 var 定义的变量会把它提升到当前函数作用
  • 踩坑vue中嵌套iframe项目,嵌套在iframe中的项目无法登录!

    解决方案原文 这个我试了下是谷歌浏览器做了限制 在edge上可以正常登录 我遇到这种情况主要是我的项目用的是cookie存储的登录状态 需要设置cookie的域名 使其在嵌入的网站和网站域名下都能访问cookie 但是我设置了还是没用 我最
  • go cli脚手架开发利器——cobra库的初体验

    文章目录 关于 说明 cobra 简介 cobra 概念 Commands Flags Args 教程正文 demo1 快速了解 demo 知识点 Command创建命令 demo2 使用参数验证器 钩子函数 demo 知识点 参数验证方法