Golang: Can you wrap a Package in an Interface?

huangapple go评论83阅读模式
英文:

Golang: Can you wrap a Package in an Interface?

问题

我正在编写一个简单的库来辅助常见的断言。

type Test interface {
    Fatalf(string, ...interface{})
}

func IsTrue(statement bool, message string, test Test) {
    if !statement {
        test.Fatalf(message)
    }
}

我注意到log包实际上有一个兼容的Fatalf(string, ...interface{})实现,如果IsTrue方法可以相应地调用它,那将非常好:

IsTrue(false, "false wasn't true", log)

但是我得到了错误use of package log not in selector。有没有办法使用或包装一个包来使这种模式工作,或者这不可能实现?

英文:

I'm writing a simple library to assist with common assertions.

type Test interface {
 	Fatalf(string, ...interface{})
}

func IsTrue(statement bool, message string, test Test) {
    if !statement {
       test.Fatalf(message)
    }
}

I noticed that the log package actually has a compatible implementation of Fatalf(string, ...interface{}) and it'd be great if the IsTrue method could be invoked accordingly:

IsTrue(false, "false wasn't true", log)

But I get the error use of package log not in selector. Is there any way to use or wrap a package to make this pattern work or is this not possible?

答案1

得分: 5

你最好的选择是将其包装在一个空白结构体中,像这样:

type internalLog struct{}

func (il internalLog) Fatalf(s string, i ...interface{}) {
    log.Fatalf(s, i...)
}

一般来说,在Go语言中,由于包不是类型,它们不能满足任何接口。你必须将它们包装在另一个类型中,以模拟它们满足接口的情况。

编辑:

正如Caleb提到的(我忘了),特定的log包具有New函数,它返回一个*log.Logger类型,该类型将满足你的情况下的Test接口(以及大多数其他包级别的log函数)。然而,一般情况下,如果没有提供这样的类型,你必须像我上面展示的那样包装该包。

英文:

The best you can hope for is to wrap it in a blank struct like so:

type internalLog struct{}

func (il internalLog) Fatalf(s string, i ...interface{}) {
    log.Fatalf(s, i...)
}

In general, since packages are not types in Go, they cannot satisfy anything. You have to wrap them in another type in order to simulate them satisfying an interface.

Edit:

As Caleb mentions (and I forgot about), the package log in specific has the function New which returns a *log.Logger which will satisfy the Test interface in your case (as well as most other package-level log functions). However, in general if no such type is provided you must wrap the package like I showed above.

答案2

得分: 2

我会使用log创建一个可以被覆盖的默认提供程序:

package main

import (
	"log"
	"os"
)

type TestLogger interface {
	Fatalf(string, ...interface{})
}

var DefaultLogger TestLogger

func init() {
	DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
}

func IsTrue(statement bool, message string) {
	if !statement {
		DefaultLogger.Fatalf(message)
	}
}

func main() {
	IsTrue(false, "MESSAGE")
}

如果有人使用你的包,他们可以这样做:

type MyCustomImplementation struct{}

func (this MyCustomImplementation) Fatalf(msg string, args ...interface{}) {
	// 在这里进行自定义操作
}

some_package.DefaultLogger = MyCustomImplementation{}
英文:

I would make a default provider using log that can be overwritten:

package main

import (
	"log"
	"os"
)

type TestLogger interface{
	Fatalf(string, ...interface{})
}

var DefaultLogger TestLogger

func init() {
	DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
}

func IsTrue(statement bool, message string) {
    if !statement {
       DefaultLogger.Fatalf(message)
    }
}

func main() {
	IsTrue(false, "MESSAGE")
}

If someone was using your package they could do something like this:

type MyCustomImplementation struct {}

func (this MyCustomImplementation) Fatalf(msg string, args ... interface{}) {
    // do whatever in here
}

some_package.DefaultLogger = MyCustomImplementation{}

huangapple
  • 本文由 发表于 2013年12月28日 01:19:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/20804913.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定