Is there a way to create a function using unexported type as parameter in Golang? - go

In my application, I have a struct for which I defined a New function to create instances as zero values of the fields are not meaningful. In addition, I didn't export the struct. So the only way to create is via New.
var goodPerson = person.New("James", "Tran")
goodPerson.PrintFullName()
On the caller side, I have no idea how to create a function that takes in the unexported type as a parameter in such a way that I can still access the exported methods of this type.
func doBadThingToGoodPeople(goodPerson <???>) {
goodPerson.PrintFullName()
}
I'd be very grateful if you could point me in a direction.

You can use an interface:
type FullNameSupport interface {
PrintFullName()
}
func doBadThingToGoodPeople(goodPerson FullNameSupport) {
goodPerson.PrintFullName()
}
This way don't have to export the type.

Related

Golang: Autocomplete missing interface methods

I am currently working on a go project where I define an interface to use in another file. My workflow works but I'm confused at either why there doesn't seem to be any "auto-complete" for protocols or why I cannot find it, I am using VSCode.
First of all, I am not fluent in go at all so if I misuse the term "object" for example that's because I don't know any better.
Let's say the interface looks like that:
type TestInterface interface {
Function1()
}
and my function to pass an object of that interface to looks like that
func Start(obj TestInterface) {
...
Now, in order to define a type that I can construct an object of, I do
type TestInterfaceType int
and because I have to conform to the interface defined, I need to apply these functions to my "new" type
func (e TestInterfaceType) Function1() {
fmt.Println("Test")
}
I am then able to construct an object
var testInterfaceTypeObject TestInterface
testInterfaceTypeObject = TestInterfaceType(1)
and passing that object to my Start() function above which expects a type of that interface works fine since the object of my "new type" has the functions defined that are defined on the interface.
Everything until here works as I have expected, or at least it works for me.
Now if I add another function to the TestInterface but I do not apply that new function to my TestInterfaceType, I see an error coming up that is InvalidIfaceAssign:
InvalidIfaceAssign occurs when a value of type T is used as an
interface, but T does not implement a method of the expected
interface.
I understand why this is happening, I also have to do the func (e TestInterfaceType) ... for my new function but here is my question:
Is there a way to automatically generate empty mock functions for the missing functions? In Java for example, the IDE offers me to add the missing functions (without functionality of course, but at least they are there, ready for me to write logic into them)?
In other words, once I add Function2() to TestInterface, can I make it automatically do
func (e TestInterfaceType) Function2() {
}
wherever I use that interface?

Is it possible to create a reflect.Type of an Interface with custom methods?

I want to define an interface's properties in reflect.Type for serialization/deserialization purposes. I've looked and there doesn't seem to be an InterfaceOf([]*Methods) function (analogous to StructOf).
My ultimate goal is to serialize and deserialize a reflect.Type using protobufs. I need to be able to recreate a function using FuncOf where one of the parameters is an interface.
Say I have a function with the signature func foo(x interface{bar()}), I can do:
reflect.TypeOf(f) // func(interface { main.t() })
// and
reflect.TypeOf(f).In(0) // interface { main.t() }
but I can't build that description. I can get the empty interface type:
itf := reflect.TypeOf((*interface{})(nil)).Elem() // interface{}
// and
FuncOf([]reflect.Type{itf}, []reflect.Type{}, false)
I see this issue which suggests that what I'm looking to do isn't possible but I was hoping there is some work around for my use case.
https://play.golang.org/p/WGgFxporB_Q

Go: Access a struct's properties through an interface{}

I am having trouble in accessing the one struct's properties (named Params) in different file.
please consider x.go where i invoke a function(CreateTodo)
type Params struct {
Title string `json:"title"`
IsCompleted int `json:is_completed`
Status string `json:status`
}
var data = &Params{Title:"booking hotel", IsCompleted :0,Status:"not started"}
isCreated := todoModel.CreateTodo(data) // assume todoModel is imported
now CreateTodo is a method on a struct (named Todo) in different file lets say y.go
type Todo struct {
Id int `json:todo_id`
Title string `json:"title"`
IsCompleted int `json:is_completed`
Status string `json:status`
}
func (mytodo Todo)CreateTodo(data interface{}) bool{
// want to access the properties of data here
fmt.Println(data.Title)
return true
}
Now I just want to use properties of data in CreateTodo function in y.go.
But i am not able to do so and getting following error
data.Title undefined (type interface {} is interface with no methods)
I am sure issue is around accepting struct as an empty interface but i am not able to figure out.
Please help here.Thanks
So you have one of two options, depending on your model:
#1
Switch to data *Params instead of data interface{} as suggested in another answer but it looks like you are expecting different types in this function, if so; check option #2 below.
#2
Use Type switches as follows:
func (t Todo) CreateTodo(data interface{}) bool {
switch x := data.(type) {
case Params:
fmt.Println(x.Title)
return true
// Other expected types
default:
// Unexpected type
return false
}
}
P.S. Be careful with your json tags: it should be json:"tagName". Notice the ""! Check go vet.
You could just type the function parameter:
func (mytodo Todo)CreateTodo(data *Params) bool{
// want to access the properties of data here
fmt.Println(data.Title)
return true
}
See: https://play.golang.org/p/9N8ixBaSHdP
If you want to operate on a Params (or *Params), you must do that.
If you want to operate on an opaque type hidden behind an interface{}, you must do that.
In short, you cannot peek behind the curtain without peeking behind the curtain. Either expose the actual type Params, so that you can look at it, or keep all the code that does look at it elsewhere. The "keep the code elsewhere" is where interface really shines, because it allows you to declare that something otherwise-opaque has behaviors and ask for those behaviors to happen:
type Titler interface {
GetTitle() string
}
If Params has a GetTitle function, it becomes a Titler.
You can now define your CreateTodo as a function that takes a Titler, and then you can pass &data to this function.
This structure is overall quite klunky and it seems much more likely that Todo itself should be an embeddable struct instead, but see a more complete example starting from a stripped-down version of your sample code here, in the Go Playground.

Composition combining data and functions with interfaces and structs

I'm wondering if this is something that's done in Go or if I'm thinking about it all wrong: composing type x interface and type x struct so my interface methods have access to specific data too:
The C programmer in my wants to do this:
type PluginHandler interface {
onLoad()
pm *PluginManager
}
func (ph PluginHandler) onLoad() {
pm.DoSomething()
}
There I have an interface defined with a function, but also some data I want to pass to those functions but this is a syntax error.
So is this something that's doable in Go through some other method or am I just thinking about the problem wrong?
You have defined onLoad incorrectly. You cannot define a function directly on interface type.
Once you have an interface, you need another type to implement methods specified in the interface. For example, if another type implements onLoad method, they automatically (implicitly) implement the interface PluginHandler.
The other thing you need to do is change the interface function type to accept the required data:
type PluginHandler interface {
onLoad(*PluginManager)
}
struct SomeType {
// ...
}
func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
pm.DoSomething() // PluginHandler interface.
}
This way, you get to inject whichever PluginManager required by PluginHandler.
Also, you can use SomeType as a PluginHandler type whereever required.
func someFuntion(ph PluginHandler) {
// ...
ph.onLoad(pm)
// ...
}
Can be called with an input argument of type SomeType:
s := SomeType{}
someFunction(s)
TL;DR; There is no direct translation to Go.
Long answer:
Go interfaces are only methods.
Go structs are only data (with the possibility of receiver methods).
You can reference, and even embed interfaces within structs:
type Frobnicator interface {
Frobnicate() error
}
type Widget struct {
Frobnicator
WidgetName string
}
But that's not really what you're talking about.
The best answer to your dilema is, I believe: Take a step back. You're focusing on the trees, and you need to look at the forest. Go takes a different approach than C, or classical OO languages like C++ and Java.
Look at the general problem to be solved, and find solutions to that in Go. This can be a painful process (I can say from experience), but it's really the only way to learn the new way of thinking.
Just for the record, you can add extra methods to an existing type, by introducing another (indirection) type as:
type HandlerManager PluginManager
func (x *HandlerManager) onLoad() {
((*PluginManager)(x)).DoSomething()
}
And if you need to go with a more generic solution, a combination of Adapter & Strategy patterns could do:
type PluginHandlerAdapter struct{ _onLoad func() }
func (x *PluginHandlerAdapter) onLoad() {
x._onLoad()
}
Used like (public/private access ignored):
type PluginManager struct {
PluginHandlerAdapter
}
func NewPluginManager() *PluginManager {
res := new(PluginManager)
res._onLoad = res.DoSomething
return res
}

Adding a method for existing type in Golang: how to rewrite return value's type

I want to extend existing goquery.Selection type with my own method and be able to use it from package's selectors. I know that I cannot "patch" existing method -- I need to create a new one. But how do I can force the existing package functions to use my new type? Something I'm missing in general or there's no "nice" way to do it and it's better to use a function?
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
)
type customSelection goquery.Selection
func (s *customSelection) CustomMethod() int {
return 1
}
doc.Find("*").Each(func(i int, s *goquery.Selection) {
fmt.Println(s.CustomMethod()) // does not works since its still "goquery.Selection"
// how do I can get a result with customSelection type here?
})
Since inheritance is not supported, the best practice is to embed the non-local type into your own local type, and extend it.
In the Design Patterns lingo its better known as composition:
https://en.wikipedia.org/wiki/Composition_over_inheritance
You can use function instead of method:
func customFunc(s *goquery.Selection) int {
return 1
}
...
fmt.Println(customFunc(s))

Resources