葵花宝典教程,一个自学编程平台

葵花宝典教程,一个自学编程平台

Golang语言小技巧1

技巧

  •  golang可以在函数定义的时候确定其返回值具体为 func foo(arg int)(res int){}

  • go env GOPATH 可以用来去查看当前的GOPATH

  • golang 查找问题, 可以根据Goglandack工具一起结合查找

  • golang中的init函数用来初始化一些变量, 它总是会被运行, 只要导入了这个包, 初始化就会在run main之前被运行

  • golang中的接口类型, 以接口类型传入参数, 如果该接口类型, 实现了方法则ok

  • proto.String() 是一个helper方法, 分配一个新的空间, 并返回一个指向它的指针

  • golang中首字母大写表示public, 首字母小写则表示protect 或者 private

  • golangdefer语句的执行顺序为逆序

  • golang中有时候为了诊断方便, 可以使用printStackruntime.Stack(buf[:], false)

  • io.Writer是golang中接口类型的一种典型的运用, Fprintf=>(Printf, SPrintf)

  • Stringer接口通常用于对于printf或者println等一些列的函数数输出

  • golang中的数组array为定长数组, 如两个数组相比较必须是comparable即长度和类型必须一致

  • golang语言定义变量或者结构体在编译期就已经复制, 在运行期赋值, 需要重新定义一个函数

  • golangflag库需要使用flag.parse()来传递参数

  • buffer channelchannel中的元素个数小于channel size时为非阻塞的, 达到channel size之后则阻塞当前线程直到元素被取出.

  • 0 buff channel即为sync channel. 生产者和消费者都会被阻塞.

  • golang中对比并行程序设计有: 设置返回channel, 以经典的生产者消费者模式进行处理.

  • timer主要是用来设置定时任务, tickers主要是用来设置周期任务.

  • 使用sync.Mutex通过对全局变量的LockUnLock实现atomic加锁和解锁

  • 对于Atomic inc也可以使用sync/atomic库实现.

  • CASCompare And Swap比较并交换, 在golang中是以共享内存方式实现的一种同步机制.

  • Share memory by communicating; don't communicate by sharing memory.

  • golang中更好的一种方式是通过sync包以及channel来实现同步机制.

  • time.Sleep vs time.After

    • time.After通常于select搭配使用, 可以设置超时机制

    • time.Sleep可读性更强, 暂停当前Goroutine, 直到达到时间.

  • timer 通过AfterFuncNewTimer来创建, 使用Reset来重置, timer. 使用Stop来停止timer, 停止timer之后, 相应的goroutine会被阻塞.

  • timer 使用时, 如果使用了timer.Stop(), 则timer, 会被GC所回收, 但是timer对应的channel不会关闭, 则channel将会被永远的阻塞.

  • timer.Stop对应的timer被GC所回收, timer.C被阻塞, 如果再使用timer.Reset,则重新给timer对应的时间赋值并放入timer.C

  • timer 使用的正确姿势是, 使用timer.Reset, 而不是使用timer.Stop. 如果使用指针并且使用对应的timer.Channel. 重置timer时, 应当使用Reset而不是重新Stop+NewTimer来重置, 这样会导致内存泄漏, 阻塞goroutine

  • deadlock死锁: 多个线程占有一部分资源, 去请求另一部分资源时阻塞. 这些线程等等其他的线程释放资源. (已请求到锁)

  • livelock:活锁, 不断请求锁, 但是无法请求到资源. (未加锁)

  • selectchannel搭配使用, 如果要实现类似listener的模式, 则需要在外层加for {select ...}.

  • 通常使用select实现函数超时机制.

  • HTTP keep-alive是保持TCP连接open, 即复用TCP连接的一种手段. 例如: 通过HTTP keep-alive就可以实现不用每次都去重新建立HTTP连接, 这样就不会重新去请求静态资源css,html等.

  • TCP keep-alive是TCP协议定时地发送空的ack包来确认彼此的状态.

  • TCP keep-aliveHTTP keep-alive是两个不同的技术, 不存在谁依赖谁的关系. TCP keep-alive用来检测对端是否存在, 而HTTP keep-alive用来协商以复用连接.

  • context上下文类型,带有deadline,取消信号,还有其他与请求相关的request-scoped的值

  • context遵循的几个原则:

    • 不要将Context放入结构体,使用Context应该作为第一个参数传入,并命名为ctx,func DoSomething(ctx context.Context, arg Arg) error {//use ctx}

    • 即使函数允许,不要传入nil的Context.如果不知道用哪种Context,使用context.TODO()

    • 使用context的Value相关的方法只应该用于在程序和接口中传递和请求相关元数据,不要用它传递可选参数

    • 相同的Context可以传递给不同的goroutine, Context并发安全

  • sync.Map go1.9支持的线程安全的map,通过cas实现

  • reflect: go语言反射机制。reflact反射是一种机制,这种机制可以实现自我类型的检查和描述

  • init函数在main函数之前执行,通常用作初始化

  • sync.Once保证程序仅仅执行一次action

  • panic类似于抛出异常,即停止当前正确的程序流程, panic之后会执行defer函数

  • recover类似于恢复异常,即panic会一直向上抛出阻碍正常流程,直到recover则恢复

  • 具体的某个golang对象初始化时候,通常的一种写法是通过OptionFunc来初始化一些可选参数

  • // +build:是golang的build tag 例如// +build linux,386 darwin,!cgo 等价于(linux AND 386) OR (darwin AND (NOT cgo))

  • go build -tags="linux 386"进行编译, 并根据Build Constraints的条件进行编译

  • golang make初始化并分配内存

  • golang %#v%+v 为打印变量并打印其变量名

  • value receiver 和 pointer receiver

    • value receiver是并发安全的, 且不改变value本身的值, copy by value

    • pointer receiver 不是并发安全的,且可以改变pointer本身的值

  • golang elastic 使用Scorll可以滚动的获取所有请求的结果

  • dep 为官网golang包管理工具

  • dep init : 效率较低,初始化golang项目的独立环境,利用gps分析出当前代码包中的依赖关系,并将其约束写入项目中的,Gopkg.toml文件中。将所有依赖的包最新的version/branch/revision信息写入Gopkg.lock,创建vendor目录,并以Gopkg.lock为输入,将其中包下载到vendor目录下面。

  • dep status: 查看当前项目下的status的状态

  • dep ensure : 确保当前项目的vendor处于一个正确的状态

  • gorilla/mux : golang 非常受欢迎的URL router dispatcher
    goconvey : golang 带UI的单元测试框架,可以很好的显示单元覆盖度

  • ACL: access control list 访问控制列表,是路由器和交换机接口的指令,用于控制端口进出的数据包,ACL提供了网络安全访问的基本手段。

  • map[string]*person{} 与 map[string]person{}的区别在于指针和实例,实例为重新copy构造,改变内容之后,不改变map本身的内容, 末尾的{}为初始化map

  • OLAPOnline Analytical Processing: 在线数据处理关注于数据分析,OLTP: Online Transaction Processing 在线事务处理,类似于增删查改,专注于查询的速度

  • 一致性hash,为了解决弹性集群动态扩容的问题,通常的做法是构造0~2^32-1个hash环状空间,对于具体的某个key找到对应服务器上节点时,只需要顺序在环上转动找到第一个命中的节点即可。当出现负载不均的情况时,可以考虑使用引入虚拟节点达到负载均衡的效果。

  • GC: Garbage collection 垃圾回收机制,常见的垃圾回收算法有: 引用计数,标记清除Mark-Sweep法,三色标记法,分代收集法。

  • 引用计数:最基础的垃圾回收算法,例如C++中的std:shared_ptr

  • 标记清除:分为两个步骤:1. Mark: 从程序的根节点开始,遍历所有的对象,对可达的节点进行标记。2. Sweep: 将所有未标记的节点对象作为垃圾进行回收清除操作。有一个问题是会有STW(Stop The World)的问题,算法进行标记时会暂停整个应用程序。当程序中的对象特别多时,遍历整个对象树会消耗很多的时间。go1.3

  • 三色标记:是Mark-Sweep的一个改进,支持并发,即可以实现on-the-fly即在程序执行的同时进行垃圾回收 go1.6. 步骤如下:

1. 首先创建三个集合:白、灰、黑。
2. 将所有对象放入白色集合中。
3. 然后从根节点开始遍历所有对象(注意这里**并不递归遍历**),把遍历到的对象从白色集合放入灰色集合。
4. 之后遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合
5. 重复 4 直到灰色中无任何对象
6. 通过write-barrier检测对象有变化,重复以上操作
7. 集所有白色对象(垃圾)


  • 分代收集:也是Mark-Sweep的一个改进。该算法基于一个经验:绝大多数的对象生命周期都很短,按照对象生命周期的长短来分代。

一般分代GC,分为3代,新生代(Young Generation),年老代(Tenured Generation),永久代(Permanent Generation)
原理如下:

1. 新对象放入第 0 代
2. 当内存用量超过一个较小的阈值时,触发 0 代收集
3. 第 0 代幸存的对象(未被收集)放入第 1 代
4. 只有当内存用量超过一个较高的阈值时,才会触发 1 代收集,2 代同理
因为 0 代中的对象十分少,所以每次收集时遍历都会非常快(比 1 代收集快几个数量级)。只有内存消耗过于



git解决冲突的四种方式是什么

四种方式:

  1. 执行命令将改动提交到远程分支。

  2. 使用“git add xxx”和“git commit -m..”将改动提交;

  3. 执行命令来手动合并冲突的内容;

  4. 使用“git fetch origin master”将远程分支拉下来;

60d57c9306e48490[3].jpg

  1. git冲突的产生原因

    多个开发者同时使用或者操作git中的同一个文件,最后在依次提交commit和推送push的时候,第一个操作的是可以正常提交的,而之后的开发者想要执行pull(拉)和pull(推)操作的时候,就会报冲突异常conflict。

    Git解决冲突的方法

    使用git fetch origin master将远程分支拉下来
    使用git merge origin master手动合并冲突的内容,首先合并代码并输入备注信息,然后按esc,再按shit+;,输入wq保存并退出
    使用git add xxx和git commit -m "xxx" 将改动提交
    使用git push origin master将改动提交到远程分支

PHP composer

composer是php包管理工具,使用它可以很方便进行构建项目,载入三方包,以及各种复杂依赖,自动加载等需要。


安装composer


curl -sS https://getcomposer.org/installer | php -- \


--install-dir=/usr/bin \


--filename=composer


安装后,使用composer -v来查看版本号等信息。


修改代码仓库源


由于composer默认的源服务器在国外,因为众所周知的原因,下载龟速,我们需要将其替换为国内的全量源,目前可用的有这两个:


来自 Laravel China


composer config -g repo.packagist composer https://packagist.laravel-china.org


来自 https://php.cnpkg.org/


composer config -g repos.packagist composer https://php.cnpkg.org


查看全部全局配置


composer config -g --list


查看单个项目全部配置


composer config --list


查看某个配置


composer config -g repositories.packagist.org


取消某一项配置


composer config -g --unset repos.packagist


创建新项目


创建一个Yii项目


composer create-project --prefer-dist yiisoft/yii2-app-basic basic.com


其中create-project命令后面的--prefer-dist还可以使用--prefer-source,它们的区别:


--prefer-dist会从github上下载.zip压缩包,并缓存到本地。下次再安装就会从本地加载,大大加速安装速度。但她没有保留 .git文件夹,没有版本信息。适合基于这个package进行开发。


--prefer-source 会从github上clone源代码,不会在本地缓存(最新的版本也可以使用缓存了)。保留了.git文件夹,从而可以实现版本控制。适合用于修改源代码。


推荐使用--prefer-dist可以加快速度,在使用的时候有可能会有下面类似的警告:


Failed to download yiisoft/yii2-gii from dist: The zip extension and unzip command are both missing, skipping.


Your command-line PHP is using multiple ini files. Run `php --ini` to show them.


环境中缺少zip,unzip工具包,安装一下:


apt-get install zip unzip


之后跟的yiisoft/yii2-app-basic就是项目包名,最后面的basic.com指定新建项目文件夹。


检索仓库里的包


composer search monolog/monolog


安装新依赖包


composer require monolog/monolog


控制版本号


# 指定版本


composer require monolog/monolog 1.24.0


# 版本范围


# 有效的运算符有 >、>=、


# 支持通配符 *


# 支付波浪号运算符 ~ 限定在最低版本和下一个重要版本更新之前


# 以下都是有效的版本号


# 版本大于等于1.0


>=1.0


# 版本大于等于1.0并且小于2.0


>=1.0,<2.0


# 版本大于等于1.0并且小于1.1,或者版本大于等于1.2


>=1.0,<1.1|>=1.2


# 相当于>=1.0,<1.1


1.0.*


# 相当于>=1.2,<2.0


~1.2


# 相当于>=1.2.3,<1.3


~1.2.3


# 相当于>=1.2.3,<2.0.0 在多于2位的版本号的时候跟 ~ 有区别


^1.2.3


移除依赖包


composer remove monolog/monolog


初始化一个composer.json


composer init


查看已存在的包


composer info


根据composer.lock安装依赖包(如果存在),否则根据composer.json


composer install


根据composer.json更新依赖到指定范围内最新版,并更新composer.lock文件


composer update


清理缓存


composer clearcache


更新composer.phar


composer self-update


Composer常用的命令整理


golang go-swagger为Go工程生成自动化接口文档

来自动生成接口文档。文档的格式支持两种:一种是json,另外一种是yaml。要想通过代码注释生成接口文档,那么你的Go工程必须放在$GOPATH/src目录下。

使用swagger:meta定义接口的全局信息

属性

标记含义

Terms Of Service描述使用接口服务的一些协议,比如免责等

Consumes描述接口默认请求的mime类型值,如果有多个,每个类型占据一行。支持的MIME类型有json,yaml,xml,txt,bin,urlform,multipartform

Produces描述接口默认响应的mime类型值,如果有多个,每个类型占据一行

Schemes描述接口默认支持的协议类型,可能的值有http,https,ws,wss

Version当前接口的版本

Host接口服务所在的域名

Base path接口默认的根路径

Contact通常来说是接口文档编写者的联系方式,格式:John Danjohn.dan@example.com

License接口文档遵循的许可证名称

示例

// Package classification testProject API.

//

// the purpose of this application is to provide an application

// that is using plain go code to define an API

//

// This should demonstrate all the possible comment annotations

// that are available to turn go code into a fully compliant swagger 2.0 spec

//

// Terms Of Service:

//

// there are no TOS at this moment, use at your own risk we take no responsibility

//

//     Schemes: http, https

//     Host: localhost

//     BasePath: /v1

//     Version: 0.0.1

//     Contact: Haojie.zhao<haojie.zhao@changhong.com>

//

//     Consumes:

//     - application/json

//     - application/xml

//

//     Produces:

//     - application/json

//     - application/xml

//

// swagger:meta

package routers


import (

"testProject/controllers"

"github.com/astaxie/beego"

)


func init() {

    beego.Router("/", &controllers.MainController{})

}

然后在命令行里执行swagger generate spec -o ./swagger.json,执行完成后会在你工程的根目录下生成一个swagger.json文件。这就是自动生成的接口文档,上面内容生成的对应文件为:

{

  "consumes": [

    "application/json",

    "application/xml"

  ],

  "produces": [

    "application/json",

    "application/xml"

  ],

  "schemes": [

    "http",

    "https"

  ],

  "swagger": "2.0",

  "info": {

    "description": "the purpose of this application is to provide an application\nthat is using plain go code to define an API\n\nThis should demonstrate all the possible comment annotations\nthat are available to turn go code into a fully compliant swagger 2.0 spec",

    "title": "testProject API.",

    "termsOfService": "there are no TOS at this moment, use at your own risk we take no responsibility",

    "contact": {

      "name": "John Dan",

      "email": "john.dan@example.com"

    },

    "version": "0.0.1"

  },

  "host": "localhost",

  "basePath": "/v1",

  "paths": {}

}

你可以在swagger Editor中查看接口文档,它会有一定样式,便于阅读。上面生成的接口文档如下图所示:

20190904141646688[1].png

使用swagger:route定义路由信息

swagger:route标记用来定义接口的路由信息,它会将路径连接到方法,此操作获取唯一id,该id在各个位置用作方法名称。语法如下:swagger:route [method] [path pattern] [?tag1 tag2 tag3] [operation id]。


属性

标记含义

Consumes描述接口支持的特定的mime类型值,如果有多个,每个类型占据一行。支持的MIME类型有json,yaml,xml,txt,bin,urlform,multipartform

Produces描述接口支持的特定的mime类型值,如果有多个,每个类型占据一行

Schemes描述接口支持的特定协议类型,可能的值有http,https,ws,wss

Responses响应状态码字典

示例

package controllers


import (

"github.com/astaxie/beego"

)


type MainController struct {

beego.Controller

}


// Get serves the API for this get index page

func (c *MainController) Get() {

// swagger:route GET / users indexPage

//

// Show index page.

//

// This will show all available users by default.

//

//     Consumes:

//     - application/json

//

//     Produces:

//     - application/json

//

//     Schemes: http, https, ws, wss

//

//     Responses:

//       default: Resp

//     422: validationError

c.Data["Website"] = "beego.me"

c.Data["Email"] = "astaxie@gmail.com"

c.TplName = "index.tpl"

}

20190904141837901[1].png

使用swagger:response定义响应

使用swagger:route可以定义响应的名称,接着需要做的就是将这些响应名称和具体的响应结果对应起来。用法:swagger:response [?response name]。语法中的response name就是你在定义swagger:route的时候,通过Response属性设置的名字。

示例

package models

// A Resp is an response that is used when the request returned.

// swagger:response Resp

type Resp struct {

// The response information

// in: body

//

Body struct{

// Required: true

Status bool        `json:"status"`

// Required: true

Code   string      `json:"code"`

// Required: true

Msg    string      `json:"msg"`

// An optional field name to which this validation applies

Data   interface{} `json:"data,omitempty"`

}

}


// A ValidationError is an error that is used when the required input fails validation.

// swagger:response validationError

type ValidationError struct {

// The error message

// in: body

Body struct {

// The validation message

//

// Required: true

Message string

// An optional field name to which this validation applies

FieldName string

}

}

20190904141951707[1].png

注意: 通过上图可以看出,响应结构体必须嵌套在你之前定义的响应结果名称之内。


使用swagger:params定义参数信息

上面已经定义了接口地址相关信息,接着定义接口的参数信息。用法:swagger:parameters [operationid1 operationid2],这里的operationid1,operationid2都是之前在定义router时确定的。例如某些接口可能会有相同的参数,我们就可以在这里使用它们operationid。


属性

标记含义

In在哪里找到参数,例如是在query中或者在path中,也可以是body

Required描述参数是否必须,true表示必须

示例

package models

// A Resp is an response that is used when the request returned.

// swagger:response Resp

type Resp struct {

// The response information

// in: body

//

Body struct{

// Required: true

Status bool        `json:"status"`

// Required: true

Code   string      `json:"code"`

// Required: true

Msg    string      `json:"msg"`

// An optional field name to which this validation applies

Data   interface{} `json:"data,omitempty"`

}

}


// A ValidationError is an error that is used when the required input fails validation.

// swagger:response validationError

type ValidationError struct {

// The error message

// in: body

Body struct {

// The validation message

//

// Required: true

Message string

// An optional field name to which this validation applies

FieldName string

}

}


// swagger:parameters indexPage

type RequestParam struct {

// in: body

//

Body struct{

// a Nickname is user nick name which is string

// Required: true

Nickname string `json:"nickname"`

Password string `json:"password"`

VerifyCode int `json:"verifyCode"`

}

}

2019090414213550[1].png

可以看到在使用swagger:parameters定义operation id为indexPage的接口路由时,也是使用定义响应结构体那种形式,通过内嵌的方式实现。


使用swagger:strfmt定义格式化的字符串

语法为:swagger:strfmt [name],默认的字符串格式名字有:


uuid,uuid3,uuid4,uuid5

email

uri(absolute)

hostname

ipv4

ipv6

credit card

isbn,isbn10,isbn13

social security number

hexcolor

rgbcolor

date

date-time

duration

password

custom string formats

示例

当我们把之前定义的请求参数,添加一个参数email,它的格式应该为邮件格式的字符串。那么可以这样定义。

// swagger:parameters indexPage

type RequestParam struct {

// in: body

//

Body struct {

// a Nickname is user nick name which is string

// Required: true

Nickname   string `json:"nickname"`

Password   string `json:"password"`

VerifyCode int    `json:"verifyCode"`

// swagger:strfmt email

Email string `json:"email"`

}

}

20190904142214340[1].pnghttps://blog.csdn.net/benben_2015/article/details/100538074

golang govalidators包 验证

go validators用法详解 对struct字段进行参数验证

golang一枚,业务中有对接口struct字段进行参数验证的需求,为了练手,自己造了个go validators验证器的轮子,代码在github,使用的详细方法写到这里,也希望大家在使用过程遇到问题来这提问

在编写golang接口时,需要对接收到的struct字段内容进行验证,比如


type Student struct {

 Uid   int64

 Name  string

 Age   int64

 Sex   string

 Email string

}

我们需要对结构体内的字段进行验证合法性:

  • Uid的值在某一个范围内

  • Name值的长度在某一个范围内

  • Sex的值符合男或女

  • Email格式正确等等

go validators可以对数据进行基本验证,也可高度定制.

安装方式如下

go get github.com/smokezl/govalidators


先来个简单例子,通过golang的structTag来配置验证器

type Class struct {
    Cid       int64  `validate:"required||integer=10000,_"`
    Cname     string `validate:"required||string=1,5||unique"`
    BeginTime string `validate:"required||datetime=H:i"`}type Student struct {
    Uid          int64    `validate:"required||integer=10000,_"`
    Name         string   `validate:"required||string=1,5"`
    Age          int64    `validate:"required||integer=10,30"`
    Sex          string   `validate:"required||in=male,female"`
    Email        string   `validate:"email||user||vm"`
    PersonalPage string   `validate:"url"`
    Hobby        []string `validate:"array=_,2||unique||in=swimming,running,drawing"`
    CreateTime   string   `validate:"datetime"`
    Class        []Class  `validate:"array=1,3"`}


  1. required 判断字段对应的值是否是对应类型的零值

  2. integer 表示字段类型是否是整数类型,如果integer后边不接=?,?,那么表示只判断是否是整数类型,如果后边接=?,?,那么有四种写法
    (1). integer=10 表示字段值 = 10
    (2). integer=_ ,10 表示字段值 <= 10,字段值最小值为字段对应类型的最小值(比如字段对应类型为int8,那么最小为−128),最大值为10
    (3). integer=10, _ 表示字段值 >= 10,字段值最小值为10,最大值为字段对应类型的最大值(比如字段对应类型为int8,那么最大为127)
    (4). integer=1,20 表示字段值 >=1 并且 <= 20

  3. arraystring 同 integer,array=?,? 表示元素个数范围,string=?,? 表示字符串长度范围

  4. email 表示字段值是否是合法的email地址

  5. url 表示字段值是否是合法的url地址

  6. in 表示字段值在in指定的值中,比如 Hobby 字段中,in=swimming,running,drawing,表示 Hobby 字段的值,只能是swimming,running,drawing中的一个或多个

  7. datetime 表示字段值符合日期类型,如果datetime后边不接=?,那么默认为Y-m-d H:i:s,否则验证器会按照指定格式判断,比如 datetime=Y-m、datetime=Y/m/d H:i:s等,可以是Y m d H i s 的随意拼接

  8. unique 表示字段值唯一,比如 Hobby 字段的 unique,表示 Hobby 字段值唯一,Class 中,Cname 字段的 unique,表示 Cname 字段值唯一


介绍了各验证器的作用,现在来开始使用吧

import (

    "fmt"

    "github.com/smokezl/govalidators"

)


validator := govalidators.New()

student := &Student{

    Uid:          1234567,

    Name:         "张三1111",

    Age:          31,

    Sex:          "male1",

    Email:        "@qq.com",

    PersonalPage: "www.abcd.com",

    Hobby:        []string{"swimming", "singing"},

    CreateTime:   "2018-03-03 05:60:00",

    Class: []Class{

        Class{

            Cid:       12345678,

            Cname:     "语文",

            BeginTime: "13:00",

        },

        Class{

            Cid:       22345678,

            Cname:     "数学",

            BeginTime: "13:00",

        },

        Class{

            Cid:       32345678,

            Cname:     "数学",

            BeginTime: "13:60",

        },

    },

}

errList := validator.Validate(student)

if errList != nil {

    for _, err := range errList {

        fmt.Println("err:", err)

    }

}

执行结果:

err: Name should be betwween 1 and 5 chars long

err: Age should be betwween 10 and 30

err: Sex is not in params [male female]

err: Email is not a email address

err: PersonalPage is not a url

err: Hobby is not in params [swimming running drawing]

err: CreateTime is not a date time

err: Cname is not unique

err: BeginTime is not a date time

有时候,我们不需要将错误全部收集到,而是只要其中一个有错,那么就返回错误,可以用 LazyValidate 方法

err := validator.LazyValidate(student)

if err != nil {

    fmt.Println("err:", err)

}

执行结果:

err: Name should be betwween 1 and 5 chars long

我们还可以对报错信息、email 正则、url 正则进行自定义,先看下各个验证器可以自定义的参数
    1. 公共 Range 类型

    type Range struct {

        Min string //最小值,外部可设置,支持0-9数字和 _ 符号,会将值赋值给 Range.min

        Max string //最大值,外部可设置,支持0-9数字和 _ 符号,会将值赋值给 Range.max

        min string //最小值,比对使用,支持0-9数字和 _ 符号,接收 Range.Min 和 struct 中传进来的值

        max string //最大值,比对使用,支持0-9数字和 _ 符号,接收 Range.Max 和 struct 中传进来的值


    /**

     * 自定义范围判断错误 msg 格式,map 的 keys 有 lessThan,equal,atLeast,between 

     * 根据类型的不同,msg 文案也不同,[min] 表示 Range.min, [max] 表示 Range.max

     * var stringErrorMap = map[string]string{

     *   "lessThan": "[name] should be less than [max] chars long",

     *   "equal":    "[name] should be equal [min] chars long",

     *   "atLeast":  "[name] should be at least [min] chars long",

     *   "between":  "[name] should be betwween [min] and [max] chars long",

     * }

     * var numberErrorMap = map[string]string{

     *   "lessThan": "[name] should be less than [max]",

     *   "equal":    "[name] should be equal [min]",

     *   "atLeast":  "[name] should be at least [min]",

     *   "between":  "[name] should be betwween [min] and [max]",

     * }

     * var arrayErrorMap = map[string]string{

     *   "lessThan": "array [name] length should be less than [max]",

     *   "equal":    "array [name] length should be equal [min]",

     *   "atLeast":  "array [name] length should be at least [min]",

     *   "between":  "array [name] length should be betwween [min] and [max]",

     * }

     */

        RangeEMsg map[string]string

    }

    1. required

    type RequiredValidator struct {

        EMsg string //自定义错误 msg 格式,默认为 [name] is must required,[name] 表示属性名,下同

    }

    1. string

    type StringValidator struct {

        EMsg  string //自定义错误 msg 格式,默认为 [name] is not a string

        Range        //涉及到判断范围(字符串长度、数组长度、数字大小)验证器的公共属性

    }

    1. integer

    type IntegerValidator struct {

        EMsg  string //自定义错误 msg 格式,默认为 [name] is not a integer

        Range        //涉及到判断范围(字符串长度、数组长度、数字大小)验证器的公共属性

    }

    1. array

    type ArrayValidator struct {

        EMsg  string //自定义错误 msg 格式,默认为 [name] is not a array/map/slice

        Range        //涉及到判断范围(字符串长度、数组长度、数字大小)验证器的公共属性

    }

    1. email

    type EmailValidator struct {

        EMsg string //自定义错误 msg 格式,默认为 [name] is not a email address

        Reg  string //自定义 email 正则

    }

    1. url

    type UrlValidator struct {

        EMsg string //自定义错误 msg 格式,默认为 [name] is not a url

        Reg  string //自定义 url 正则

    }

    1. in

    type InValidator struct {

        EMsg     string //自定义错误 msg 格式,默认为 [name] is not in params [args]

        TypeEMsg string //自定义类型错误 msg 格式,默认为 [name] type invalid

    }

    1. datetime

    type DateTimeValidator struct {

        EMsg   string //自定义错误 msg 格式,默认为 [name] is not a date time

        FmtStr string //自定义Y m d H i s 组合,默认为 Y-m-d H:i:s

    }

    1. unique

    type UniqueValidator struct {

        EMsg string //自定义错误 msg 格式,默认为 [name] is not unique

    }

    如果我们想把刚才的报错信息,都改为中文,那么就可以对每个验证器错误 msg 进行自定义

    validator := govalidators.New()

    validator.SetValidators(map[string]interface{}{

        "string": &govalidators.StringValidator{

            Range: govalidators.Range{

                RangeEMsg: map[string]string{

                    "between": "[name] 长度必须在 [min] 和 [max] 之间",

                },

            },

        },

        "integer": &govalidators.IntegerValidator{

            Range: govalidators.Range{

                RangeEMsg: map[string]string{

                    "between": "[name] 的值必须在 [min] 和 [max] 之间",

                },

            },

        },

        "in": &govalidators.InValidator{

            EMsg: "[name] 的值必须为 [args] 中的一个",

        },

        "email": &govalidators.EmailValidator{

            EMsg: "[name] 不是一个有效的email地址",

        },

        "url": &govalidators.UrlValidator{

            EMsg: "[name] 不是一个有效的url地址",

        },

        "datetime": &govalidators.DateTimeValidator{

            EMsg: "[name] 不是一个有效的日期",

        },

        "unique": &govalidators.UniqueValidator{

            EMsg: "[name] 不是唯一的",

        },

    })

    errList := validator.Validate(student)

    if errList != nil {

        for _, err := range errList {

            fmt.Println("err:", err)

        }

    }

    执行结果:

    err: Name 长度必须在 1 和 5 之间

    err: Age 的值必须在 10 和 30 之间

    err: Sex 的值必须为 [male female] 中的一个

    err: Email 不是一个有效的email地址

    err: PersonalPage 不是一个有效的url地址

    err: Hobby 的值必须为 [swimming running drawing] 中的一个

    err: CreateTime 不是一个有效的日期

    err: Cname 不是唯一的

    err: BeginTime 不是一个有效的日期

    如果现有的验证器不够用,还可以进行自定义,只需要满足 ValidatorF 函数类型 或 Validator 接口就可以

    ValidatorF 类型

    type ValidatorF func(params map[string]interface{}, val reflect.Value, args ...string) (bool, error)

    Validator 接口

    type Validator interface {

        Validate(params map[string]interface{}, val reflect.Value, args ...string) (bool, error)

    }

    例子

    type UserValidator struct {

        EMsg string

    }


    func (self *UserValidator) Validate(params map[string]interface{}, val reflect.Value, args ...string) (bool, error) {

        fmt.Println("=====", "UserValidator")

        return true, nil

    }


    func userMethod(params map[string]interface{}, val reflect.Value, args ...string) (bool, error) {

        fmt.Println("=====", "userMethod")

        return true, nil

    }

    validator.SetValidators(map[string]interface{}{

        "user": &UserValidator{},

        "vm":   userMethod,

    })

    errList := validator.Validate(student)

    if errList != nil {

        for _, err := range errList {

            fmt.Println("err:", err)

        }

    }

    struct 中,增加 user 和 vm 验证

    Email        string   `validate:"email||user||vm"`

    执行结果:

    ===== UserValidator

    ===== userMethod

    来源https://www.cnblogs.com/yangxinpython/p/13161454.html

    golang decimal插件大数字处理

    package main
    
    import (
       "fmt"
    
       "github.com/shopspring/decimal"
    )
    
    func main() {
       price, _ := decimal.NewFromString("136.02")//获取数字
       quantity := decimal.NewFromFloat(3)//
    
       fmt.Println(quantity)
       fee, _ := decimal.NewFromString(".035")
       taxRate, _ := decimal.NewFromString(".08875")
    
       subtotal := mul(price, quantity)
       preTax := mul(subtotal, add1(fee, decimal.NewFromFloat(1)))
       total := mul(preTax, add1(taxRate, decimal.NewFromFloat(1)))
       taxes := sub(total, preTax)
       taxRate = div(sub(total, preTax), preTax)
    
       fmt.Println("int,Subtotal:",int(subtotal))
       fmt.Println("float64,Subtotal:",float(subtotal))
    
       fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
       fmt.Println("Pre-tax:", preTax)    // Pre-tax: 422.3421
       fmt.Println("Taxes:", taxes)       // Taxes: 37.482861375
       fmt.Println("Total:", total)       // Total: 459.824961375
       fmt.Println("Tax rate:", taxRate)  // Tax rate: 0.08875
    }
    
    // 加法
    func add1(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
       return d1.Add(d2)
    }
    
    // 减法
    func sub(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
       return d1.Sub(d2)
    }
    
    // 乘法
    func mul(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
       return d1.Mul(d2)
    }
    
    // 除法
    func div(d1 decimal.Decimal, d2 decimal.Decimal) decimal.Decimal {
       return d1.Div(d2)
    }
    
    // int
    func int(d decimal.Decimal) int64{
       return d.IntPart()
    }
    
    // float
    func float(d decimal.Decimal) float64{
       f, exact := d.Float64()
       if !exact{
          return f
       }
       return 0
    }


    PuTTY 新手使用教程

    PuTTY 经常用于 Windows 下连接管理远程服务器。本文配合截图介绍 PuTTY 的基础用法及一些设置技巧.

    PuTTY 下载及相关工具包

    在下载页提供有集成 PuTTY 及相关工具的完整安装包

    putty.exeSSH 和 Telnet 客户端(最常使用的)
    pscp.exeSCP 客户端,命令行下通过 SSH 远程拷贝文件
    psftp.exeSFTP 客户端,命令行下的文件传输会话
    puttytel.exe一个单纯 Telnet 客户端
    plink.exePuTTY 后端的命令行工具
    pageant.exePuTTY、PSCP、Plink 的 SSH 认证代理
    puttygen.exeRSA、DSA、ECDSA 和 EdDSA 密钥生成工具

    PuTTY 创建 SSH 会话连接

    运行 putty.exe,输入服务器 IP 地址和端口(22 是 SSH 默认端口),选中 SSH 连接类型,设置连接会话名称及点击保存,点击 Open 按钮连接登录。

    putty-tutorial-1[1].png

    首次连接会提示服务器指纹,选择是或否。“是”将保存指纹,“否”则不保存。

    putty-tutorial-2[1].png

    之后输入用户名和密码即可登录服务器


    putty-tutorial-3[1].png


    如果需要注销连接会话使用  Ctrl+d 快捷键。


    PuTTY 修改保存设置

    如果需要修改 PuTTY 默认设置,就选中修改 Default Setting


    putty-tutorial-4[1].png

    PuTTY 会话保持时间

    当与长时间没数据传输时,PuTTY 会自动断开连接。要避免该问题,可以在 Connection 选项 Seconds between keepalives 里开启会话保持功能即可

    putty-tutorial-5[1].png

    PuTTY 复制粘贴文本

    在 SSH 会话窗口不能 Ctrl+C 这样的快捷键(liunxCtrl+C 是终止命令执行),复制粘贴需要用鼠标。复制操作先用鼠标左键拖拽选中,然后单击选中部分即可复制。


    PuTTY 窗口内容长度

    在 Windows 选项里修改 Lines of scrollback 数值可以调整PuTTY 会话窗口的长度

    putty-tutorial-6[1].png

    PuTTY 保存登录用户名

    如果登录服务器用同一个用户账号,可以设置会话默认登录用户名,免去每次输入麻烦。在 Connection 选项 Date 里设置。

    putty-tutorial-7[1].png

    PuTTY 使用私钥登录


    依次打开 Connection -> SSH -> Auth 选项,浏览选中私钥文件,保存设置后即可使用密钥方式登录。

    putty-tutorial-8[1].png

    如果登录提示下面错误,是因为 PuTTY 不支持 PEM 格式密钥。需要用 puttygen.exe 程序转换一下。

    运行 puttygen.exe,点击 Load 导入私钥文件,然后点击 Save private key 另存为 ppk 后缀密钥文件。

    putty-tutorial-9[1].png

    PuTTY 删除会话配置信息

    除了在 PuTTY 选项里删除连接会话外,也可以直接删除软件注册表信息。

    到此,PuTTY 使用方法就介绍到这里了。关于文件传输,建议用支持图形化界面的 SFTP 软件,如 WinSCP、FileZilla 这些




    vmware使用教程及虚拟机安装linux

    https://www.cnblogs.com/zln1021/p/9552722.html

    xftp的使用教程

    使用xftp来上传,下载文件到linux主机

    首先,我们要下载一个xftp

    时已经安装完成,点击finish,打开软件登录SSH账号,这里以默认的root账号演示。

    1、关闭登陆弹出来的“会话”窗口:

    2、填入账号信息:

    注意sftp连接需要前缀sftp再加上IP地址或域名(实列. sftp://www.jennal.cn),然后是账号和密码;点击连接。

    3、SSH安全警告(接受并保存,只在首次登陆提示):

    上传下载功能:sftp客户端跟普通的FTP一样,拖动文件就可以了;而且中文界面也很方便。自定义编辑器:在Xftp界面中,工具 -> 选项 -> 高级 -> 编辑器路径,选择自

    定义编辑器的路径就可以了


    在自定义编辑器中,保存文本,Xftp即自动上传修改后的文档。


    Xshell入门使用教程

    Xshell 是一个强大的远程管理软件,它支持TELNET,SSH 协议。Xshell可以在Windows下访问远端服务器、路由器、网络机顶盒等,类似的常用软件还有putty,以及Telnet等待。

    Xshell的几个特点:

    • 可以保存密码,注意安全,尽量不要保存,除非个人电脑。

    • 支持标签,打开多个服务器时候很方便,点击标签切换。

    • 界面设计简洁、人性,使用方便。


    Xshell下载安装及基本使用方法:

    1、从网上搜索下载,注意别下载错了。

    2、打开xshell。


    3、个性化设置。设置好,用起来更顺手。经过这样设置,以后使用事半功倍。其他地方,根据自己的喜好,可以进行相关设置。

    4、连接服务器或路由器。点击打开。

    5、点击左上角,新建

    6、填写完,点击确定。其他高级参数,有需要可以填写。常用的主机或路由器,可以点击身份验证,填写用户名和密码,这样不需要输入就可以直接登录系统了。

    7、第一次连接会出现提示,如下图。

    8、登录成功,可以输入相关命令,进行各种操作。

    xshell几个常用命令以及注意事项:

    cd .. 回到上级目录

    cd jennal.cn 进入jennal.cn目录

    rm jennal.cn 删除文件jennal.cn

    rm -rf 删除目录及其所包含的所有文件,高危命令,一定谨慎

    mkdir jennal.cn 创建目录jennal.cn

    vi 查看/编辑文件 按 i进入编辑模式;按Esc键退出编辑模式。按:q退出不保存; 按:wq保存退出。




    << < 1 2 3 4 5 6 7 8 9 10 > >>

    Copyright www.jennal.cn Rights Reserved葵花宝典教程.鄂icp2022001145号-1

    分享:

    支付宝

    微信