Golang struct not fulfilling interface requirement in method return type

Issue

I have a simple method to write a string to a file as follows:

type IFile interface {
    WriteString(s string) (n int, err error)
}

func writeStrToFile(createFile func(string) (IFile, error), data string) {
    file, _ := createFile(getFilePath())
    file.WriteString(data)
}

Assume getFilePath() returns a valid file path string for the current OS

I attempt to invoke the function writeStrRefreshTokenToFile() using the following:

writeStrToFile(os.Create, "DATA")

From what I understand, os.Create‘s return method signature of func(name string) (*os.File, error) should fulfill writeStrToFile‘s parameter type requirement of func(string) (IFile, error) because *os.File should be a valid implementation of the interface IFile. However, in implementation I get an IncompatibleAssign error. Why is this?


Context:
Ultimately, I am trying to write unit tests for this function such that I can expect that the createFile() and WriteString() functions are invoked properly. I’m new to Go so it’s possible I’m just approaching this wrong and don’t need to be so thorough about testing the implementation of the function. However, with no return values, it would seem the function is untestable otherwise

Solution

The error message tells you that a type func(name string) (*os.File, error) cannot be used as a type func(string) (IFile, error). The function signatures are different: *os.File and IFile are different types.

Assuming that Go worked as you expected, there’s another issue. The program leaks the file descriptor returned from os.Create.

An alternative way to structure code is like this:

func writeStrToFile(writeFile func(name string, data []byte, perm FileMode) error, data string) {
    writeFile(getFilePath(), []byte(data), 0666)
}

Call it like this normally:

writeStrToFile(os.WriteFile, "DATA")

Replace os.WriteFile with another function for testing.

Answered By – kelly

Answer Checked By – Jay B. (GoLangFix Admin)

Leave a Reply

Your email address will not be published.