Go:属性存在,但Go编译器说不存在?

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

Go: Property exists but Go compiler says it doesn't?

问题

filelogger.go

package logger

import (
	"io"
)

type FileLogger struct{
	File io.Writer
}

func NewFileLogger(file io.Writer) *FileLogger{
	return &FileLogger{file}
}

func (this *FileLogger) Log(message string) error {
	_, err := this.File.Write([]byte(appendNewLine(message)))

	return err
}

filelogger_test.go:

package logger

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

type WriterMock struct{
	data []byte
}

func (this WriterMock) Write(b []byte) (n int, err error) {
	this.data = append(this.data, b ...)

	return len(this.data), nil
}

func NewMockedFileLogger() *FileLogger{
	writer := WriterMock{}

	fileLogger := FileLogger{writer}

	return &fileLogger
}

func TestLog(t *testing.T) {
	fileLogger := NewMockedFileLogger()

	fileLogger.Log("Hello World!")

	assert.Equal(t, "Hello World!", string(fileLogger.File.data))
}

我的问题:

当运行go test时,我收到以下错误消息:

fileLogger.File.data未定义(类型io.Writer没有字段或方法data)

file.Logger.File确实是type io.Writer,但是这个字段data是存在的,我知道Go是一种强类型语言,所以它不接受这个。

如何解决这个问题?

英文:

filelogger.go

package logger

import (
	"io"
)

type FileLogger struct{
	File io.Writer
}

func NewFileLogger(file io.Writer) *FileLogger{
	return &FileLogger{file}
}

func (this *FileLogger) Log(message string) error {
	_, err := this.File.Write([]byte(appendNewLine(message)))

	return err
}

filelogger_test.go:

package logger

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

type WriterMock struct{
	data []byte
}

func (this WriterMock) Write(b []byte) (n int, err error) {
	this.data = append(this.data, b ...)

	return len(this.data), nil
}

func NewMockedFileLogger() *FileLogger{
	writer := WriterMock{}

	fileLogger := FileLogger{writer}

	return &fileLogger
}

func TestLog(t *testing.T) {
	fileLogger := NewMockedFileLogger()

	fileLogger.Log("Hello World!")

	assert.Equal(t, "Hello World!", string(fileLogger.File.data))
}

My problem:

I'm getting this error message when running go test:

fileLogger.File.data undefined (type io.Writer has no field or method data)

file.Logger.File is indeed of type io.Writer, but this field data exists, I know Go is a strongly typed language, that's why it's not accepting this.

How can solve this?

答案1

得分: 3

FileLogger中,File是一个接口(io.Writer),而不是一个结构体。

要访问WriterMockdata,你需要进行类型断言

fileLooger.File.(*WriterMock).data

(注意:如果File不是*WriterMock类型,这将失败:下面会详细说明)


请参考这个简化的示例

package main

import "fmt"
import "io"

type WriterMock struct {
    data []byte
}

func (this WriterMock) Write(b []byte) (n int, err error) {
    this.data = append(this.data, b...)

    return len(this.data), nil
}

func main() {
    var w io.Writer = &WriterMock{}
    fmt.Printf("Hello, playground '%+v'", w.(*WriterMock).data)
}

输出:

Hello, playground '[]'


由于类型断言可能出错,你应该始终检查错误,请参考“接口转换和类型断言”一节:

> 但是,如果发现值不包含字符串,程序将崩溃并出现运行时错误。
为了防止这种情况发生,可以使用“逗号,ok”的习惯用法来安全地测试值是否为字符串:

str, ok := value.(string)
if ok {
    fmt.Printf("string value is: %q\n", str)
} else {
    fmt.Printf("value is not a string\n")
}
英文:

The writer File in a FileLogger is an interface (io.Writer), not a struct.

You would need a type assertion in order to access data of WriterMock:

fileLooger.File.(*WriterMock).data

(Note: that would fail if File was not a *WriterMock: more on that below)


See this simplified example:

package main

import "fmt"
import "io"

type WriterMock struct {
	data []byte
}

func (this WriterMock) Write(b []byte) (n int, err error) {
	this.data = append(this.data, b...)

	return len(this.data), nil
}

func main() {
	var w io.Writer = &WriterMock{}
	fmt.Printf("Hello, playground '%+v'", w.(*WriterMock).data)
}

Output:

Hello, playground '[]'


Since a type asertion car error, and you should always check the error, consider the section "Interface conversions and type assertions":

> But if it turns out that the value does not contain a string, the program will crash with a run-time error.
To guard against that, use the "comma, ok" idiom to test, safely, whether the value is a string:

str, ok := value.(string)
if ok {
    fmt.Printf("string value is: %q\n", str)
} else {
    fmt.Printf("value is not a string\n")
}

huangapple
  • 本文由 发表于 2015年3月8日 23:42:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/28928337.html
匿名

发表评论

匿名网友

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

确定