go - 如何实现我自己的文件类型?
问题描述
我有一个打开文件并使用该函数写入文件的os.OpenFile
函数。
我基本上想做的是模拟它返回的文件以编写测试。因为我想更好地理解 Go,所以我想在不使用第三方包的情况下做到这一点。
这是我尝试过的:
我的包裹
package logger
import (
"fmt"
"time"
"sync"
"os"
"strings"
"path/filepath"
"io"
)
const timestampFormat = "2006-01-02 15:04:05.999999999"
type FileOpener interface {
OpenFile(name string, flag int, perm os.FileMode) (*os.File, error)
}
type RotateWriter struct {
fileOpener FileOpener
lock sync.Mutex
filename string
fp *os.File
}
type defaultFileOpener struct{}
func (fo defaultFileOpener) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(name, flag, perm)
}
func CreateRotateWriter(filename string, fileOpener FileOpener) (RotateWriter) {
if (fileOpener == nil) {
return RotateWriter{filename: filename, fileOpener: defaultFileOpener{}}
}
return RotateWriter{filename: filename, fileOpener: fileOpener}
}
func (writer RotateWriter) Write(bytes []byte) (int, error) {
writer.lock.Lock()
defer writer.lock.Unlock()
extension := filepath.Ext(writer.filename)
filename := strings.TrimSuffix(writer.filename, extension)
// There is a specific constants that are used for formatting dates.
// For example 2006 is the YYYYY, 01 is MM and 02 is DD
// Check https://golang.org/src/time/format.go line 88 for reference
fullFilename := filename + time.Now().UTC().Format("-2006-01-02") + extension
// Open the file for the first time if we don't already did so
if writer.fp == nil {
fp, err := os.OpenFile(fullFilename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return 0, err
}
writer.fp = fp;
}
// We are now pointing to a different file. Close the previous one and open a new one
if fullFilename != writer.fp.Name() {
writer.fp.Close()
fp, err := os.OpenFile(fullFilename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return 0, err
}
writer.fp = fp;
}
return writer.fp.Write([]byte("[" + time.Now().UTC().Format(timestampFormat) + "] " + string(bytes)))
}
我希望在我的测试包中做的是这样的
type file interface {
io.Closer
io.Reader
io.ReaderAt
io.Seeker
Stat() (os.FileInfo, error)
}
type fileType struct{
fd int
name string
contents string // Where I'll keep the in-memory contents maybe
}
type defaultFileOpener struct{
}
func (fo defaultFileOpener) OpenFile(name string, flag int, perm os.FileMode) (*file, error){
return &fileType{1, name, ""}, nil //Cannot use &fileType{1, name, ""}(type *fileType) as type *file
}
func (f fileType) Write(bytes []byte) (int, error){
f.contents += string(bytes)
return len(bytes), nil
}
我很可能误解了一些东西,甚至可以在 go 中创建我自己的文件类型吗?
解决方案
从片段中不清楚是否*fileType
实现了file
接口的所有方法,但如果没有,您应该首先确保它实现了。因为如果不是这样,您将无法按照您的意愿在测试中使用它。
您的文件打开器的OpenFile
方法应该将接口作为其返回类型,而不是指向接口的指针。那是:
func (fo defaultFileOpener) OpenFile(name string, flag int, perm os.FileMode) (file, error) {
这是因为*file
与 的类型不同file
,并且实现file
接口的类型的值(例如 yours *fileType
)不能在预期指向该接口的指针的地方使用。
并且返回指向接口的指针几乎从来都不是您真正想要的,如果您想使用指针间接将接口值切换为另一个接口值,那么这样做可能是有意义的,但这里似乎并非如此。如果您浏览标准库,您将很难找到返回指向接口类型的指针的函数/方法......
但是假设这就是你想要做的,那么你必须返回一个指向接口类型值的指针,而不是一个指向实现接口的类型的指针。
例如
var f file = &fileType{} // f is of type file
return &f, nil // &f is of type *file
请记住,它f
的类型必须是file
返回工作,如果它只是*fileType
它不会编译。
var f = &fileType{} // f is of type *fileType
return &f, nil // &f is of type **fileType
推荐阅读
- reactjs - 如何使用 SPA 或 Web 应用在 Okta 中获取 refresh_token
- mysql - SQL在WHERE子句中添加条件
- python - Dash/Plotly DataTable 组件的响应性问题
- python - 如果没有,则合并熊猫中的列
- python - 从 Python 调用 Tableau Prep 流程
- android - 在手机屏幕中移动 Pg
- django - Django 模型翻译
- swift - 在 Mapbox iOS SDK 中使用 Bing 地图
- ruby-on-rails - 为什么rails使用redis?
- qt - 通过插件编写将菜单操作添加到 Qt Designer