可以修改其他包中定义的类型的方法集吗?

时间:2013-01-01 08:43:47

标签: logging go

内置loglog.Logger不提供ErrorWarning方法,例如Python

所以我想使用以下代码为内置Logger类型编写一个:

func (l *Logger) Error(v interface{}) {
    info := fmt.Sprintf("ERROR: %v", v)
    l.Println(info)
}

我将上面的代码放在morelog.go下的GOPATH/src/log文件中。

在我写的main.go中:

logger := log.New(os.Stdout, "Test", 1)
logger.Error("Error in main.")

当我运行go build时,我得到:

./main.go:124: logger.Error undefined (type *log.Logger has no field or method Error)

我知道我可以通过定义新类型并在该类型上定义方法来实现类似的目标。但我认为如果我可以将方法直接添加到buit-in类型可能会更好。

3 个答案:

答案 0 :(得分:5)

这两个答案都是正确的,所以我会提出更多的选择。您无法在未定义的类型上定义方法。函数确实是你可以做到这一点的一种方法,但你也可以通过重新定义类型或包装类型来实现。

例如,如果您不关心拆分outfile并且只想修改日志行,那么您可以执行以下操作之一。

重新定义类型:

type MyLogger log.Logger

func (l MyLogger) Info(msg string, args ...interface{}) {
    log.Logger(l).Printf(msg, args...)
}

func (l MyLogger) Error(msg string, args ...interface{} {
    log.Logger(l).Printf("ERROR: " + msg, args...)
}

或换行类型:

type MyLogger struct {
  log.Logger
}

func (l MyLogger) Info(msg string, args ...interface{}) {
  l.Printf(msg, args...)
}

func (l MyLogger) Error(msg string, args ...interface{}) {
  l.Printf("ERROR: " + msg, args...)
}

重新定义类型会将您可以调用的方法集限制为您定义的方法集。如果不首先进行转换,您将无法重用* Printf方法。通过嵌入来包装类型将允许您调用* Printf方法并使用您自己的方法包装这些方法。您可以在每种情况的Info和Error方法的实现中看到这样的示例。

答案 1 :(得分:4)

Rputikar对您的基本问题的答案是正确的。您无法在未创建的类型上定义新方法。

然后,一个解决方案就是不要挂断方法,只需编写一个普通的函数。这是您希望作为函数编写的方法。

Edit2:正如Spirit Zhang正确指出的那样,我的第一个版本的代码在Lshortfile或Llongfile标志的情况下丢失了行号。这是一个改进:

func LogError(l *log.Logger, v interface{}) {
    l.Output(2, fmt.Sprint("ERROR: ", v))
}

在游乐场完成工作示例:http://play.golang.org/p/MJaKQLt24L

如果将此代码放在morelog.go中,则可以将morelog.go放在主程序的目录中。或者不要为一些小函数单独使用文件;只需将LogError和LogWarning代码放在与主程序相同的文件中即可。

编辑:默认记录器示例:Edit2:此示例不适用于Lshortfile或Llongfile。我会将其保留在此处,以便人们可以看到问题。我不知道编写这些函数以使用默认记录器的简单方法。

我的示例显示了适用于任何记录器的LogError函数。如果您只需要记录默认记录器的错误,那就更简单了:

func LogError(v interface{}) {
    log.Printf("ERROR: %v", v)
}

甚至,

func LogError(v interface{}) {
    log.Print("ERROR:", v)
}

答案 2 :(得分:2)

您无法在未创建的类型上覆盖该方法。同样,您无法在未创建的类型上定义新方法。

根据您的需要,您可以简单地将两个log.Logger实例用于警告,一个用于出错。

http://play.golang.org/p/DQjIvk-wfI

package main

import (
    "log"
    "os"
)

func main() {

    errorLogger := log.New(os.Stderr, "ERROR: ", log.LstdFlags)
    warnLogger := log.New(os.Stdout, "WARNING: ", log.LstdFlags)

    errorLogger.Println("Hello, playground")
    warnLogger.Println("Hello, playground")
}