dsfdsfdsfdsf1223 2016-07-28 14:30
浏览 207
已采纳

io.MultiWriter与golang的传递值

I'd like to create a situation where everything set to a particular log.Logger is also appended to a particular variable's array of strings.

The variable's type implements the io.Writer interface so it should be easy to add that via io.MultiWriter to log.New(), but I seem to have run into an intractable problem: the io.Writer interface is fixed and it's impossible for the variable to reference itself given golang's pass-by-value.

Maybe it will make more sense with an example:

package main

import "fmt"
import "io"
import "log"
import "os"
import "strings"

var Log *log.Logger

type Job_Result struct {
    Job_ID int64
    // other stuff
    Log_Lines []string
}

// satisfies io.Writer interface
func (jr Job_Result) Write (p []byte) (n int, err error) {
    s := strings.TrimRight(string(p),"
 ")
    jr.Log_Lines= append(jr.Log_Lines,s)
    return len(s), nil  
}

func (jr Job_Result) Dump() {
    fmt.Println("
Here is a dump of the job result log lines:")
    for n, s := range jr.Log_Lines{
        fmt.Printf("\tline %d: %s
",n,s)
    }
}

func main() {

    // make a Job_Result

    var jr Job_Result
    jr.Job_ID = 123
    jr.Log_Lines = make([]string,0)

    // create an io.MultiWriter that points to both stdout 
    // and that Job_Result var

    var writers io.Writer
    writers = io.MultiWriter(os.Stdout,jr)

    Log = log.New(writers,
       "",
       log.Ldate|log.Ltime|log.Lshortfile)

    // send some stuff to the log

    Log.Println("program starting")
    Log.Println("something happened")
    Log.Printf("last thing that happened, should be %drd line
",3)

    jr.Dump()   

}

This is the output, which is not surprising:

2016/07/28 07:20:07 testjob.go:43: program starting
2016/07/28 07:20:07 testjob.go:44: something happened
2016/07/28 07:20:07 testjob.go:45: last thing that happened, should be 3rd line

Here is a dump of the job result log lines:

I understand the problem - Write() is getting a copy of the Job_Result variable, so it's dutifully appending and then the copy vanishes as it's local. I should pass it a pointer to the Job_Result...but I'm not the one calling Write(), it's done by the Logger, and I can't change that.

I thought this was a simple solution to capturing log output into an array (and there is other subscribe/unsubscribe stuff I didn't show), but it all comes down to this problematic io.Write() interface.

Pilot error? Bad design? Something I'm not grokking? Thanks for any advice.

  • 写回答

1条回答 默认 最新

  • dongshao8471 2016-07-28 14:36
    关注

    redefine the write function (is now pointer receiver)

    // satisfies io.Writer interface
    func (jr *Job_Result) Write (p []byte) (n int, err error) {
        s := strings.TrimRight(string(p),"
     ")
        jr.Log_Lines= append(jr.Log_Lines,s)
        return len(s), nil  
    }
    

    initialize

    jr := new(Job_Result) // makes a pointer.
    

    rest stays as is. This way, *Job_Result still implements io.Writer, but doesn't lose state.

    The go tutorial already said, when a method modifies the receiver, you should probably use a pointer receiver, or the changes may be lost. Working with a pointer instead of the actual object has little downside, when you want to make sure, there is exactly one object. (And yes, it technically isn't an object).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献