How to return a struct variable in a method - go

This program does not compile. It shows that the Env method is not available on the struct sample on method call. I can access the Env variable directly in the main program, but I'm curious to know why this is not compiling.
package main
//Sample is a struct
type Sample struct {
Env string
}
func main() {
pa := &Sample{Env: "acd"}
pa.call()
}
func (p *Sample) call() *Sample.Env {
return &p.Env
}

Function types are defined by the keyword func, followed by an optional receiver, followed by the function name, the parameter list between parentheses (which may be empty), and the result list (which may be empty), and then the function body.
The result list (zero or more types) is the contract for what the function will return. It can be a list of types or a list of named parameters including their types.
In your function definition for call():
func (p *Sample) call() *Sample.Env {
Your result list does not meet this expectation. *Sample.Env is a pointer to the Env property of type Sample, but not a type itself.
Your function returns value &p.Env. If you modify your function signature so that the result list is simply the type of &p.Env, then your program will run. p.Env is a string, therefore &p.Env is a pointer to a string. *string is the type "pointer to a string." Therefore if you change your function signature to this your code will work:
func (p *Sample) call() *string {
See:
Function Types
Types
Post script
The return type of call() is *string -- that is, a pointer to a string. So to print it you simply dereference it to a string with the asterisk:
env := pa.call()
fmt.Printf("Env is %s\n", *env)

Related

Why are structure functions the same type as ordinary functions

In following codes:
type of struct Struct.Test is void func(), the function can get all parameters in Struct t, why the types of Struct.func() and func() are the same
type Struct struct {
Val string
}
func (t *Struct) Test() {
println(t.Val)
}
func main() {
t := Struct{
Val: "Struct",
}
f := t.Test
f()
f = func() {
println("Hello world!")
}
f()
}
t.Test is a method value:
If the expression x has static type T and M is in the method set of type T, x.M is called a method value. The method value x.M is a function value that is callable with the same arguments as a method call of x.M. The expression x is evaluated and saved during the evaluation of the method value; the saved copy is then used as the receiver in any calls, which may be executed later.
The x.Test() method has no parameters, so x.Test is a function without parameters. The receiver x is saved internally and used when you call the x.Test function value later. Its type will be func(), so type of f is also func(), to which you can assign any value that also has a type of func().
Don't confuse method values with method expressions:
If M is in the method set of type T, T.M is a function that is callable as a regular function with the same arguments as M prefixed by an additional argument that is the receiver of the method.
The method expression is "applied" on a type, while a method value is "applied" on a value. Method expression results in a function value that includes the receiver type (as the first parameter), method value does not (the receiver is saved internally).
So in your case the method expression would be (*Struct).Test (note the pointer: Test() has pointer receiver), and it's a function with type func(Struct). It may be used / called like this:
f2 := (*Struct).Test
f2(&t)
Which again outputs Struct, try it on the Go Playground.

What does it mean for a function to have a method?

I'm seeing the following type definition:
type Getter func(ctx *context.T, key string) (Ticket, error)
And the following method defined on it:
func (g Getter) GetData(ctx *context.T, path ...string) (data []byte, err error) {
…
}
I'm also seeing the following variable definition:
var Client Getter = func(ctx *context.T, key string) (Ticket, error) {
return …
}
where:
type Ticket interface {
…
}
What'll happen with this code exactly?
tl;dr It won't compile because Cannot use 'func() (MyData, error) { return nil, nil }' (type func() (MyData, error)) as the type Getter. In other words, MyGetter does not match the type of Getter. Here's a go playground link.
There are a couple of things going on here:
You're creating a type called Getter. Any value that fulfills this Getter type must be a function with zero input parameters and zero output parameters (keep this in mind for a second).
Go has first-class functions which means they can be assigned to variables, passed to parameters of other functions, or in this case methods can be added to a type whose underlying type is a function.
Lastly, you're trying to assign a function with the signature func() (MyData, error) to the type Getter which is where you're getting the compile error I mentioned in the tl;dr. This compile error is because your type Getter specifies that any value of this type must be a function with zero input parameters and zero return parameters. You're trying to assign a function that does have return parameters.

Passing an arbitrary function as a parameter in Go

I'm trying to expand my knowledge of Go's function pointers, and I have a question about what is and is not possible with passing functions as parameters in Go.
Let's say that I want to write a decorator() function that can wrap any existing function. For simplicity, let's limit this to functions that accept exactly one parameter and return exactly one value.
If I write a decorator that accepts func(interface{}) interface{} as it's argument, it will implicitly work as long as that function I pass in also accepts/returns an interface{} type (see funcA).
My question is--is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
package main
import (
"fmt"
)
func decorate(inner func(interface{}) interface{}, args interface{}) interface {} {
fmt.Println("Before inner")
result := inner(args)
fmt.Println("After inner")
return result
}
func funcA(arg interface{}) interface{} {
fmt.Print("Inside A, with arg: ")
fmt.Println(arg)
return "This is A's return value"
}
func funcB(arg string) string {
fmt.Print("Inside B, with arg: ")
fmt.Println(arg)
return "This is B's return value"
}
func main() {
// This one works. Output is:
//
// Before inner
// Inside A, with arg: (This is A's argument)
// After inner
// This is A's return value
//
fmt.Println(decorate(funcA, "(This is A's argument)"))
// This doesn't work. But can it?
//fmt.Println(decorate(funcB, "(This is B's argument)"))
}
This is not possible. One reason for that is the mechanics of passing parameters differ from function to function, and using an interface{} arg does not mean "accept anything". For example, a function taking a struct as an arg will receive each member of that struct, but a function taking an interface{} containing that struct will receive two words, one containing the type of the struct, and the other containing a pointer to it.
So, without using generics, the only way to implement this is by using an adapter function.
Use the reflect package to handle functions with arbitrary argument and result types.
func decorate(inner interface{}, args interface{}) interface{} {
fmt.Println("Before inner")
result := reflect.ValueOf(inner).Call([]reflect.Value{reflect.ValueOf(args)})
fmt.Println("After inner")
return result[0].Interface()
}
Run the code on the playground.
Like the decorate function in the question, the function in this answer assumes one argument and one result. The function must be modified to handle other function types.
The OP should consider the tradeoffs between the anonymous wrapper function proposed in the question and the use of the reflect package here. Calling the function through the reflect API is slower than calling the function through the anonymous wrapper. There's also a loss of type safety with the reflect API. The anonymous wrapper function adds verbosity.
For the record, with Go 1.18 and the introduction of generics, the decorator function becomes almost trivial.
You may declare a type constraint as such:
type UnaryFunc[T any] interface {
func(T) T
}
The constraint itself is parametrized with T to allow for unary functions that take and return arbitrary types.
In the decorate function you then instantiate the constraint with a type parameter. The signature becomes:
decorate[T any, F UnaryFunc[T]](inner F, arg T) T
Thanks to type inference, you can just pass concrete arguments to the function, and both T and F will be unambiguous.
Example alternatives without a named constraint:
// accept and return T
decorate[T any](inner func(T) T, arg T) T
// only return T
decorate[T any](inner func() T) T
// return T and error
decorate[T any](inner func(T) (T, error), arg T) (T, error)
// N-ary function
decorate[T, U any](inner func(T, U) (T, error), argt T, argu U) (T, error)
The obvious limitation is that the interface constraint UnaryFunc specifies only functions that take and return exactly one arg of type T. You can't do otherwise, because the type set of an interface constraint may include types which support the same operations — and calling with one arg is not compatible with calling with N args.
The full program:
package main
import (
"fmt"
)
type UnaryFunc[T any] interface {
func(T) T
}
func decorate[T any, F UnaryFunc[T]](inner F, arg T) T {
fmt.Println("before inner")
result := inner(arg)
fmt.Println("after inner")
return result
}
func funcA(arg int) int {
fmt.Println("inside A with:", arg)
return arg
}
func funcB(arg string) string {
fmt.Println("inside B with:", arg)
return arg
}
func main() {
// this works
decorate(funcA, 200)
// this also works
decorate(funcB, "Func B")
}
Playground: https://go.dev/play/p/3q01NiiWsve
is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
No. It's that simple: No.

Is empty interface in golang as function argument is Pass by Value or pointer

If I have function like this
func TestMethod ( d interface{} ) {
}
If I am calling this as
TestMethod("syz")
Is this pass by value or pass by pointer ?
To summarise some of the discussion in the comments and answer the question:
In go everything in Go is passed by value. In this case the value is an interface type, which is represented as a pointer to the data and a pointer to the type of the interface.
This can be verified by running the following snippet (https://play.golang.org/p/9xTsetTDfZq):
func main() {
var s string = "syz"
read(s)
}
//go:noinline
func read(i interface{}) {
println(i)
}
which will return (0x999c0,0x41a788), one pointer to the data and one pointer to the type of interface.
Updated: Answer and comments above are correct. Just a lite bit of extra information.
Some theory
Passing by reference enables function members, methods, properties,
indexers, operators, and constructors to change the value of the
parameters and have that change persist in the calling environment.
Little code sniped to check how function calls work in GO for pointers
package main_test
import (
"testing"
)
func MyMethod(d interface{}) {
// assume that we received a pointer to string
// here we reassign pointer
newStr := "bar"
d = &newStr
}
func TestValueVsReference(t *testing.T) {
data := "foo"
dataRef := &data
// sending poiner to sting into function that reassigns that pointer in its body
MyMethod(dataRef)
// check is pointer we sent changed
if *dataRef != "foo" {
t.Errorf("want %q, got %q", "bar", *dataRef)
}
// no error, our outer pointer was not changed inside function
// confirms that pointer was sent as value
}

convert function type in Golang

// Each type have Error() string method.
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
// type error interface {
// Error() string
// }
func (f binFunc) Error() string {
return "binFunc error"
}
func func_type_convert() {
var err error
err = binFunc(add)
fmt.Println(err)
fmt.Println(i)
}
I have two questions about the code above:
I don't know why the Error method executed, when add function was converted into binFunc type?
Why the add function converted result was able to assign to an err error interface variable?
error is an interface:
type error interface {
Error() string
}
This means that any type which has a method: Error() string fulfills the interface and can be assigned to a variable of type error.
binFunc has such a method:
func (f binFunc) Error() string {
return "binFunc error"
}
New developers in Go sometimes find this confusing because they don't realize it's possible to attach methods to more than just structs. In this case binFunc is defined liked this:
type binFunc func(int, int) int
So the way this works is you are allowed to convert any function which has the same signature: (from the spec)
A function type denotes the set of all functions with the same parameter and result types.
So if you create a function add:
func add(x, y int) int {
return x + y
}
You are allowed to convert this into a binFunc:
binFunc(add)
And because of the Error method on binFunc we defined above, we are then able to assign this new binFunc to a variable of type error:
var err error
var bf binFunc = binFunc(add)
err = bf
fmt.Println's behavior is to call .Error() on errors for you:
If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
So to answer your questions:
The Error method is executed because fmt.Println looks for arguments of type error, invokes .Error() and prints the resulting string.
You are allowed to assign binFuncs to err because binFunc has an Error method. You cannot assign add directly to err because it does not have an Error method. But you are allowed to convert add to a binFunc because they have the same function signature, and by doing so you can then assign it to the err variable.
go spec dependencies:
type casting or conversion -> assignability -> type identity
explicit type casting or conversion
binFunc and func(int, int) int have same underlying representation.
binFunc(add)
note, type casting can happen between 2 types that have the same underlying representation. However, their type can be totally different.
type MyInt int
func main() {
var b MyInt = 3
a := int(b)
fmt.Println(a, b)
}
variable assignment
check type identity
based on type identity rule, binFunc is identical to func(int, int) int. So you can do type casting as below:
A named type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types.
func(int, int) int
is type literal, and it's unnamed.
type binFunc func(int, int) int
is a named type.
Predeclared types, defined types, and type parameters are called named types. An alias denotes a named type if the type given in the alias declaration is a named type.
named type is different from others. but here, binFunc is compared with the un-named type: their underlying type literals are structurally equivalent, both func(int, int) int.
var bfunc binFunc = add
check assignability
variable of named type can be assigned with a value of unnamed type providing their underlying type is identical.
You may call this an implicit type conversion here, but it's not accurate. At least golang doesn't call this type conversion because the underlying type/representation is the same.
inspired by this answer
extra words
type assertion only requires type identity. Therefore, the rule is simpler than type assignability.

Resources