Can't access method from another package by var.MethodName() - go

I have a package containing some structure and functions associated with it:
package samplepkg
type SampleStruct struct {
FirstString string
SecondString string
}
func init() {
// some operations
}
func CheckSomething(s *SampleStruct) bool {
// check something
}
Now I'm trying to run this function in another package:
import (
"MyProject/samplepkg"
)
func testFunc() {
var s = samplepkg.SampleStruct{"a", "b"}
if s.CheckSomething() {
// do some operations
}
}
But I get an error that s.CheckSomething is undefined. (&s).CheckSomething gives the same result. I can access s.FirstString and s.SecondString as well as use this method by calling
if samplepkg.CheckSomething(&s) {
// do some operations
}
But I feel it could be written in a better way. I'm aware that Go is not object-oriented language but is method invocation like this possible?

In Golang a Method set is defined as:
A type may have a method set associated with it. The method set of an
interface type is its interface. The method set of any other type T
consists of all methods declared with receiver type T. The method set
of the corresponding pointer type *T is the set of all methods
declared with receiver *T or T (that is, it also contains the method
set of T). Further rules apply to structs containing embedded fields,
as described in the section on struct types. Any other type has an
empty method set. In a method set, each method must have a unique
non-blank method name.
There is a mistake because you are using the pointer receiver with method when calling the function. So change the function when defining to method as:
func init() {
// some operations
}
func(s *SampleStruct) CheckSomething() bool {
// check something
}
Or when calling the method it should be function with argument SampleStruct which will be like
import (
"MyProject/samplepkg"
)
func testFunc() {
var s = &samplepkg.SampleStruct{"a", "b"}
if CheckSomething(s) {
// do some operations
}
}

Related

Golang: How to embed interface with different type parameters?

The code gives me error: DB redeclared.
Is there any idiomatic way to solve it? Or any work-around?
TIA
type a struct {
DB[int64]
DB[string]
}
type b interface {
DB[int64]
DB[string]
}
type DB[T any] interface {
GetList(query string) ([]T, error)
}
You can't embed the same interface, even with different type parameters. Regardless of how it is instantiated, you are trying to promote into the b interface two methods with the same name GetList and different signatures — given by the different instantiations of DB.
The situation is similar, although not technically the same, for embedding into a struct. In structs, the name of the embedded field is the name of the type — DB —, and a struct can't have two non-blank fields with the same name.
About how to solve this issue, it depends what you want to accomplish.
If you want to convey that "a implements DB with either type parameter" you can embed DB[T] and make a itself generic, and restrict a's type parameters:
type a[T int64 | string] struct {
DB[T]
}
// illustrative implementation of the DB[T] interface
// if you embed DB[T] you likely won't use `a` itself as receiver
func (r *a[T]) GetList(query string) ([]T, error) {
// also generic method
}
This is okay because DB's type parameter is constrained to any, and a's type parameter is more restrictive. This allows you to use a in other generic methods, or choose a specific type upon instantiation, but the implementation of GetList has to be parametrized too.
Otherwise if you need a to have separated methods that return int64 or string, you must give it different names.
Finally, you can embed instances of DB into two interfaces with different names, and then embed those into a instead.
type a struct {
DBStr
DBInt
}
type DBStr interface {
DB[string]
}
type DBInt interface {
DB[int64]
}
This way though the top-level selector isn't available because the method names are still the same. The program compiles, but you'll have to explicitly choose which field to call the method on:
myA := a{ /* init the two fields */ }
res, err = myA.DBStr.GetList(query)
// res is type []string
// or
res, err = myA.DBInt.GetList(query)
// res is type []int64

Refactoring method to be part of an interface

I am an ex python dev sometimes struggling with the explicit nature of Go.
I am trying here to refactor some code in order to be able move a method from one structure to be part of an interface.
But the process seems weird to me, I wish to confirm I am not doing something incorrectly.
I have the following interfaces, structure and methods:
type Executing interface {
Execute()
}
type MyExecuter struct {
attribut1 string
}
//The function I wish to move
func (exe1 *MyExecuter) format() string {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
func (exe1 *MyExecuter) Execute() {
//Executing
fmt.Println(exe.format())
}
func GetExecuter () Executer{
return MyExecuter{attribut1: "test"}
}
So here I have a generic interface Execute, this interface will be accessed by the object returned by the GetExecuter method.
Now, as part of the implementation of one of my Executer, I want to move the Format method as part of an interface.
So I am doing the following:
type Formatting interface {
format() string
}
type Formatter struct {}
func (formatter *Formatter) format(exe1 *MyExecuter) (string) {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
So I create a new interface, a new empty structure, and update my function to take as attribute my previous structure.
While this seems to work, it seems to me this is a bit convoluted. Specially the part where I need to add a reference to my initial object as attribute of the method. Am I doing something wrong here, or this is the right way?
Your Executer implementation already implements the Formatting interface:
type Executing interface {
Execute()
}
type Formatting interface {
format() string
}
func (exe1 MyExecuter) format() string {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
func (exe1 MyExecuter) Execute() {
//Executing
fmt.Println(exe.format())
}
v:=MyExecuter{}
// Here, v implements Executing and Formatting interfaces
One thing to note here: Your code shows pointer receivers. That means the methods are defined for *MyExecuter, but not for MyExecuter. So you have to pass pointers to the struct instance for this to work. Or, as I did above, use the value receivers so the methods are defined for both MyExecuter and *MyExecuter.

How to call an embedded struct method of an object passed as interface?

My scenario requires the user to embed a base struct and implement an interface.
Then, an instance of that struct should be passed to a function. The function needs to call a method of the base struct. This fails
// Given base struct and interface
type Interface interface {
Do()
}
type BaseStruct struct {
i int
s string
}
func (*b BaseStruct) Stuff() {}
// The user needs to create a struct that embeds BaseStruct and to implement Interface:
type CustomStruct struct {
*BaseStruct
}
func (*c CustomStruct) Do() {}
// The user now instantiates the struct and needs to call a function
inst := CustomStruct{}
SomePackageFun(&inst)
// The below function receives the custom struct, and must call the base struct's method, but this fails
func SomePackageFunc(i Interface) {
// declaring the function with Interface works but I can't call the methods of BaseStruct
i.Stuff() // not recognized by the compiler
}
If you want to be able to call a method on a variable of an interface type, you should add that method to the interface. Methods that come from embedded structs count for the purpose of satisfying interfaces. To call anything that isn't part of the interface, you have to assert to a concrete type (or a different interface type that has that method), which defeats the point.

golang initializing struct with embedded template: too few values in struct initializer

I'm trying to initialize a golang struct with an embedded template. Since templates have no fields, I would expect that assigning the correct number of variables to a constructor would work, but instead the compiler complains that
main.go:17:19: too few values in struct initializer
package main
import "fmt"
type TestTemplate interface {
Name() string
}
type TestBase struct {
name string
TestTemplate
}
func New(name string) *TestBase {
return &TestBase{name} // This fails
//return &TestBase{name: name} // This works
}
func (v *TestBase) Name() string {
return v.name
}
func main() {
fmt.Println(New("Hello"))
}
https://golang.org/ref/spec#Struct_types
An embedded field is still a field, the name of which is derived from its type, therefore TestBase has actually two fields and not one, namely name and TestTemplate.
This compiles just fine:
var t *TestBase
t.TestTemplate.Print()
So when initializing TestBase you either specify the field names or you initialize all fields.
These all compile:
_ = &TestBase{name, nil}
_ = &TestBase{name: name}
_ = &TestBase{name: name, TestTemplate: nil}
_ = &TestBase{TestTemplate: nil}
It looks like (as far as general concepts go) you're confusing interfaces with composition (which is kind of how Go approaches the whole inheritance question.
This post might be helpful for you: https://medium.com/#gianbiondi/interfaces-in-go-59c3dc9c2d98
So TestTemplate is an interface.
That means that the struct TestBase will implement the methods (whose signature is) defined in the interface.
You should implement Print for TestBase.
But in anycase the error you're getting is because when you initialize a struct with no field names specified, it expects all the field names to be entered, see
https://gobyexample.com/structs
So remove the composition TestTemplate from the struct (and implement the method defined in the interface instead), and it should work.
Also, FYI, the Stringer interface with String method is what fmt.Println expects to print an arbitrary struct (not a Print method) see: https://tour.golang.org/methods/17

Golang, call method from struct without variable

Is it possible to call method from struct without variable with this struct type?
//models.go
type MyStruct struct {
id int
name string
}
func (s MyStruct) GetSomeAdditionalData() string {
return "additional data string"
}
//app.go
func main() {
fmt.Println(models.MyStruct.GetSomeAdditionalData()) // not works
var variable models.MyStruct
fmt.Println(variable.GetSomeAdditionalData()) // it worked
}
Or maybe Go have other method to add some data for struct?
Or maybe I select wrong way to do it? :)
You can use a struct literal or a nil pointer.
MyStruct{}.GetSomeAdditionalData()
(*MyStruct)(nil).GetSomeAdditionalData()
To say you can. MyStruct.GetSomeAdditionalData() is called method expression and you must provide first argument of type MyStruct to that call. Argument can be anonymous composite literal MyStruct.GetSomeAdditionalData(MyStruct{}).
Here is working example https://play.golang.org/p/Wc_DjqnpLC . But all that looks not very sensible.
You can define a package function (without any receiver).
It differs from a method, as a method needs a receiver.
func GetSomeAdditionalData() string {
return "additional data string"
}
Which you can call directly, without any instance of the struct MyStruct needed (since you don't need any of MyStruct data anyway):
func main() {
fmt.Println(models.GetSomeAdditionalData())
fmt.Println(GetSomeAdditionalData())
(the second form works if you are in the package models already)

Resources