itoagolang的简单介绍

发布时间:2022-11-26

本文目录一览:

  1. golang const and itoa 2022-03-23
  2. golang logger输出格式怎么修改
  3. golang标准库的strconv函数的解释说Itoa是FormatInt(i, 10) 的简写,FormatInt(i, 10)又是什么意思呢

golang const and itoa 2022-03-23

golang const定义常量时,如果出现省略的行,则自动沿用上一行的assignment。

golang logger输出格式怎么修改

  1. Logger结构 首先来看下类型Logger的定义:
    type Logger struct {
        mu     sync.Mutex // ensures atomic writes; protects the following fields
        prefix string     // prefix to write at beginning of each line
        flag   int        // properties
        out    io.Writer  // destination for output
        buf    []byte     // for accumulating text to write
    }
    
    主要有5个成员,其中3个我们比较熟悉,分别是表示Log前缀的 "prefix",表示Log头标签的 "flag",以及Log的输出目的地 outbuf 是一个字节数组,主要用来存放即将刷入 out 的内容,相当于一个临时缓存,在对输出内容进行序列化时作为存储目的地。mu 是一个 mutex,主要用来作线程安全的实现,当有多个 goroutine 同时往一个目的刷内容的时候,通过 mutex 保证每次写入是一条完整的信息。
  2. std及整体结构 在前一篇文章中我们提到了 log 模块提供了一套包级别的简单接口,使用该接口可以直接将日志内容打印到标准错误。那么该过程是怎么实现的呢?其实就是通过一个内置的 Logger 类型的变量 "std" 来实现的。该变量使用:
    var std = New(os.Stderr, "", LstdFlags)
    
    进行初始化,默认输出到系统的标准输出 os.Stderr,前缀为空,使用日期加时间作为 Log 抬头。 当我们调用 log.Print 的时候是怎么执行的呢?我们看其代码:
    func Print(v ...interface{}) {
        std.Output(2, fmt.Sprint(v...))
    }
    
    这里实际就是调用了 Logger 对象的 Output 方法,将日志内容按照 fmt 包中约定的格式转义后传给 Output。Output 定义如下:
    func (l *Logger) Output(calldepth int, s string) error
    
    其中 s 为日志没有加前缀和 Log 抬头的具体内容。该函数执行具体的将日志刷入到对应的位置。
  3. 核心函数的实现 Logger.Output 是执行具体的将日志刷入到对应位置的方法。 该方法首先根据需要获得当前时间和调用该方法的文件及行号信息。然后调用 formatHeader 方法将 Log 的前缀和 Log 抬头先格式化好放入 Logger.buf 中,然后再将 Log 的内容存入到 Logger.buf 中,最后调用 Logger.out.Write 方法将完整的日志写入到输出目的地中。 由于写入文件以及拼接 buf 的过程是线程非安全的,因此使用 mutex 保证每次写入的原子性。
    l.mu.Lock()
    defer l.mu.Unlock()
    
    buf 的拼接和文件的写入放入这个后面,使得在多个 goroutine 使用同一个 Logger 对象时,不会弄乱 buf,也不会杂糅地写入。 该方法的第一个参数最终会传递给 runtime.Callerskip,指的是跳过的栈的深度。这里记住给 2 就可以了。这样就会得到我们调用 log 时所处的位置。 在 golang 的注释中说锁住 runtime.Caller 的过程比较重,这点我还是不是很了解,只是从代码中看到其在这里把锁打开了。
    if l.flag(Lshortfile|Llongfile) != 0 {
        // release lock while getting caller info - it's expensive.
        l.mu.Unlock()
        var ok bool
        _, file, line, ok = runtime.Caller(calldepth)
        if !ok {
            file = "???"
            line = 0
        }
        l.mu.Lock()
    }
    
    formatHeader 里面首先将前缀直接复制到 Logger.buf 中,然后根据 flag 选择 Log 抬头的内容,这里用到了一个 log 模块实现的 itoa 的方法,作用类似 C 的 itoa,将一个整数转换成一个字符串。只是其转换后将结果直接追加到了 buf 的尾部。 纵观整个实现,最值得学习的就是线程安全的部分。在什么位置合适做怎样的同步操作。
  4. 对外接口的实现 在了解了核心格式化和输出结构后,再看其封装就非常简单了,几乎都是首先用 Output 进行日志的记录,然后在必要的时候做 os.Exit 或者 panic 的操作,这里看下 Fatal 的实现。
    func (l *Logger) Fatal(v ...interface{}) {
        l.Output(2, fmt.Sprint(v...))
        os.Exit(1)
    }
    
    // Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
    func (l *Logger) Fatalf(format string, v ...interface{}) {
        l.Output(2, fmt.Sprintf(format, v...))
        os.Exit(1)
    }
    
    // Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
    func (l *Logger) Fatalln(v ...interface{}) {
        l.Output(2, fmt.Sprintln(v...))
        os.Exit(1)
    }
    
    这里也验证了我们之前做的 Panic 的结果,先做输出日志操作,再进行 panic。

golang标准库的strconv函数的解释说Itoa是FormatInt(i, 10) 的简写,FormatInt(i, 10)又是什么意思呢

两个参数是:要输入的数,返回几进制。 10 表示 10 进制;如果输入一个大于 10 的值,就会用 a-z 的字母表示更高的数字; 比如 16 进制时,a=10, b=11, c=12...