Why can't I call an interface with a collection of methods from the main package?

I am really new to golang and I am trying to see how encapsulation really works in go.

I have the following structure:

-- package a
    -a_core.go
    -a.go
    -models.go
-- main.go

In models.go I have structs for request and responses for an api call,

a.go has an empty struct which is private and a public interface which I want to expose with various methods
a_core.go just has some business logic which would be called in my interface implementation
Then I have a main.go where I just call the public interface.

package a

type myFunction struct{}

type MyFunc interface {
	Create(myData *MyData) (*MyData, error)
	Fetch(test string)
	Delete(test string)
}

//Concrete implementations that can be accessed publicly
func (a *myFunction) Create(data *MyData) (*MyData, error) {
	return nil, nil	
}

func (a *myFunction) Fetch(test string) {

}

func (a *myFunction) Delete(test string) {

}

In main.go, I call the interface my first create the MyData pointer with values

    data := &a.MyData{
     /////
   }

   result, err := a.MyFunc.Create(data)

I get the following error when I do this,

too few arguments in call to a.MyFunc.Create

cannot use data (variable of type *a.MyData) as a.MyFunc value in argument to a.MyFunc.Create: missing method CreatecompilerInvalidIfaceAssign

Please what am I doing wrong?

Yup - I’m also a noob and ran into this the other day.

First issue is that you’ve made myFunction private.

Second issue is that to access an Interface method with a pointer receiver you have to:

  1. Create a concrete version of the struct.
  2. Cast the address to the interface.

I think you’ll find that this works:

package main

import "fmt"

type MyFunction struct{}

type MyInterface interface {
	Create(myData *MyData) (*MyData, error)
	Fetch(test string)
	Delete(test string)
}

type MyData struct {
	S string
}

func (a *MyFunction) Create(data *MyData) (*MyData, error) {
	return nil, nil
}

func (a *MyFunction) Fetch(test string) {

}

func (a *MyFunction) Delete(test string) {

}

func main() {
	myFunc := MyFunction{}
	var myInt MyInterface = &myFunc
	md, _ := myInt.Create(&MyData{})
	fmt.Println(md)
}

As I say I’m a noob so the usual warnings apply. Hopefully an expert will chime in if I’m off track here.

I’ve been using Go for a few years now, but I don’t think I’d call myself an expert at anything!

@scotpip’s answer is correct: It shows you how to take a concrete thing (i.e. MyFunction), “convert” it into an interface, MyInterface, and then call a method on it.

That being said, using an interface here, in this case, is forced. Based on your question, I suspect this is just a learning experience to first start dabbling in interfaces and see how they work, and I don’t want to knock that; feel free to ask additional questions! Nothing against scotpip’s answer or your question, but I wanted to perform my “duty” as a gopher and explicitly say that you could just use your MyFunction directly instead of first converting it to an interface in this case.

Interfaces are a great utility when you don’t care about the exact type of a thing you’re using and instead only care what you can do with it.

For example, let’s say you want your program to write logging messages out for debugging. There’s already a log package that will do that for you, but let’s say it wasn’t there and you wanted to do something simple. You could do something like this:

// logger holds on to the writer that log messages will be written
// to.
var logger io.Writer = os.Stdout // by default, write to
                                 // standard output

// SetLogger allows the program logging output to be changed to
// another target.
func SetLogger(w io.Writer) {
    logger = w
}

// log a message from the application to the logger
func log(message string, args ...interface{}) {
    fmt.Fprintf(logger, message, args...)
}

func main() {
    log("starting application...")
    num, den := 3, 0
    res := div(num, den)
    fmt.Println("%d ÷ %d = %d", num, den, res)
    log("exiting application...")
}

func div(num, den int) int {
    if den == 0 {
        log("attempt to divide %d by 0", num)
        return 0 // TODO: Return an error instead of just 0
    }
    return num / den
}

Then what if instead of writing out to the console, you wanted to write to a file? You could just change the logger:

func main() {
    // ...
    f, err := os.Create("log.txt")
    if err != nil {
        panic(err) // TODO: Handle errors here better.
    }
    defer f.Close()
    SetLogger(f)
    // ...
}

If your program doesn’t care where your log messages are written to, just as long as whatever it is, it has a Write method, then an interface is a perfect fit.

Sean

Thanks for the input, but unless I’m misunderstanding something I don’t think that your logger example addresses the issue.

The original question asks how to call an interface method that has a pointer receiver.

The best resources I could find showed the two-step approach of initialising the struct, then initialising the interface with the address of the struct.

With the interface, you can call the method with the pointer receiver.

It’s not exactly elegant, but it works. If there’s a cleaner approach it would be useful to see it, but for now, this is the best I’ve got:

myStruct := MyStruct{} 

var myInterface MyInterface = &myStruct
	
myResult := myInterface.MyPointerReceiverMethod())

I didn’t intend to answer the question; I said in my last post that your answer was correct :slightly_smiling_face:. My point is that other than to demonstrate how to use interfaces in Go, there’s no point to using an interface here, in this case. You could just use MyFunction (or the MyStruct in your last post) directly:

myStruct := MyStruct{}

myResult := myStruct.MyPointerReceiverMethod()

Your answer is correct in that it shows how to convert a concrete type into an interface and call a method on that interface. I suspected that Gbubemi’s (or some other reader’s that could come to this forum post) next question might have been why use an interface in the first place, which I wanted to comment on here.

Hello all,
The responses helped. The example was just a simple one and I was building a library so, I needed to expose functions using interfaces based on my background in C# and Java.