Function types in Go - go

I'm trying to understand function types in Go, so I tried with the below code.
package main
import "fmt"
func myfn1(i string) {
fmt.Println(i)
}
func myfunc2(firstName string, lastName string) string {
return "Hello "+ firstName + " " + lastName + "!"
}
func test(do func(string), val string) {
do(val)
}
func test1(t func(string,string), fname string, lname string) string {
opt := t(fname, lname)
return opt
}
func main() {
test(myfn1, "Aishu")
greet := test1(myfunc2, "Aishu","S")
fmt.Println(greet)
}
And it throws below error.
t(fname, lname) used as value
cannot use myfunc2 (type func(string, string) string) as type func(string, string) in argument to test1
I'm not sure what I'm doing wrong.
Playground

Function types are described in Golang Spec as:
A function type denotes the set of all functions with the same
parameter and result types.
Here it is clearly mentioned that function with same parameter and result types
There are different functions definition that you are passing to your main program and the definitions that your function requires. If you look at below function carefully you have passed t as argument to test1 which returns nothing but you are assign its value to opt that's why the error.
t(fname, lname) used as value
For second error which says:
cannot use myfunc2 (type func(string, string) string) as type
func(string, string) in argument to test1
Since because if you look at the type of function you are passing to test1 as an argument and the type of argument that you have defined in test1 are different.
Please check below working code.
package main
import "fmt"
func myfn1(i string) {
fmt.Println(i)
}
func myfunc2(firstName string, lastName string) string{
return "Hello "+ firstName + " " + lastName + "!"
}
func test(do func(string), val string){
do(val)
}
func test1(t func(string,string) string, fname string, lname string) string{
opt := t(fname,lname)
return opt
}
func main() {
test(myfn1, "Aishu")
greet := test1(myfunc2, "Aishu","S")
fmt.Println(greet)
}
Playground example

You have two unrelated problems.
The first:
t(fname, lname) used as value
Is that you're trying to assign the return value of t(fname, lname) to a variable, but t() doesn't return anything.
The second:
cannot use myfunc2 (type func(string, string) string) as type func(string, string) in argument to test1
Is pretty self-explanatory. You're trying to pass a function that returns a string func(string, string) string, to a function that expects a function that returns nothing func(string, string).

Related

How to properly use variadic args in Golang?

I am complete beginner with Go and I am trying to pass variadic args to encodeit method as a string that will hash the string, otherwise pass an empty string. I wan't to print out hashed string.
I have tried multiple things, but could not get it to work.
package main
import(
"crypto/sha512"
"encoding/hex"
"fmt"
)
func encodeit(content string) string {
sha_512 := sha512.New()
sha_512.Write([]byte(content))
contentH := sha_512.Sum(nil)
contentHash := hex.EncodeToString([]byte(contentH))
return contentHash
}
func some(payload ...string) {
if len(payload) == 1 {
contentHash := encodeit(payload)
} else {
contentHash := encodeit("")
}
return contentHash
}
func main() {
fmt.Println(some(`{"stockSymbol": "TSLA"}`))
}
Here is the error log
# command-line-arguments
.\stackOverflow.go:19:26: cannot use payload (type []string) as type string in argument to encodeit
.\stackOverflow.go:23:2: too many arguments to return
.\stackOverflow.go:23:9: undefined: contentHash
.\stackOverflow.go:27:18: some("{\"stockSymbol\": \"TSLA\"}") used as value
payload becomes an array of strings ([]string) when using an ellipsis (...). It can be iterated on using a key,value for loop:
func printEncoded(payload ...string) {
for i, value := range payload {
fmt.Println(i, encode(value))
}
}
Use printEncoded("TSLA","AMD","DOW") and you won't have to create your own []string array as an argument ([]string{"TSLA","AMD","DOW"}).
You're also going to want to take a look at the JSON package for parsing: {"stockSymbol": "TSLA"}
Fixed Playground
check your func return value:
func some(payload ...string) string
you missed the return type string.

Golang: Passing structs as parameters of a function

Trying to teach myself some Go by following an online course. And I'm trying to go a bit off course to expand on my learning a bit.
The course had us writing a simple function using a couple variables and the function would take the two variables and print out a line. So I had:
func main() {
var greeting := "hello"
var name := "cleveland"
message := printMessage(greeting,name)
fmt.Println(message)
}
func printMessage(greeting string, name string) (message string) {
return greeting + " " + name + "!"
}
Later the course introduced a way to create an pseudo-array of strings using the using the
func sayHello (cities ...string) (message string) {
for _, city := range cities {
message := printMessage("hello", city)
fmt.Println(message)
}
}
I would like to create a struct with different greetings and pass those into the sayHello function. So the struct and the variables would looks something like this:
type cityInfo struct {
greeting string
name string
wins float32
gamesPlayed float32
}
city1 := cityInfo{"hello", "cleveland"}
city2 := cityInfo{"good morning", "atlanta"}
...and so on
How do I format the function to pass those structs into the function so that I can iterate on the number of structs and get the greetings and names using city.greeting and city.name? Does this question make sense?
Function argument type can be any valid type:
func sayHello (cities ...cityInfo) {
for _, city := range cities {
message := printMessage(city.greeting, city.name)
fmt.Println(message)
}
}
One solution would be to create an interface and a greeting method.
For example:
type Greetable interface {
Greeting() string
Name() string
}
You would then implement the Greeting and Name methods in your struct (this would immediately implement the Greetable interface, due to the way that Go handles interfaces):
type cityInfo struct {
name string
greeting string
}
func (city *cityInfo) Greeting() string {
return city.greeting
}
func (city *cityInfo) Name() string {
return city.name
}
And then your function would just accept anything that implements Greetable:
func sayHello(greetables ...Greetable) (message string)
And use the Name() and Greeting() methods instead.

How to return from function types when using closures in Go

Im new to GoLang and cannot figure out whats wrong in the code below. What i'm trying to do is "Create and return Printer function on the fly"
type Salutation struct { name string
greeting string
}
type Printer func(s string) string
func Greet2(salutation Salutation, do func(string)) (string){
do(salutation.name + " " + salutation.greeting)
return "Done"
}
func createPrintFunction(custom string) Printer {
return func(s string) string {
return "hello"
}
}
func pluralSightModule1Closures1(w http.ResponseWriter, r *http.Request) {
var s = Salutation{"Joe", "Hello"}
res := Greet2(s, createPrintFunction("!!!"))
w.Header().Set("Content-Type", "application/json")
w.Write([]byte (res))
}
I get the following compilation error
cannot use createPrintFunction("!!!") (type Printer) as type func(string) in argument to Greet2
The problem is the signatures don't match. That includes the return type.
Greet2 wants func(string) but createPrintFunction returns func(s string) string. Note that Greet2's returns nothing, but the createPrintFunction function returns a string.
You'll have to decide how to make them match. You probably want to use the return value in Greet2 for something better than "Done".
func Greet2(salutation Salutation, do func(string) string) string {
return do(salutation.name + " " + salutation.greeting)
}
Since you've defined type Printer func(s string) string its best to use it consistently to avoid this sort of problem. Greet2 takes a Printer and createPrintFunction returns a Printer. Then if Printer changes things will still work.
func Greet2(salutation Salutation, do Printer) string {
return do(salutation.name + " " + salutation.greeting)
}
...but the do generated by createPrintFunction doesn't use its arguments. It's hard to advise what it should do because much of this code just passes its arguments straight through, or ignores them.
Anyhow, the signatures have to match.
Solution:
func Greet2(salutation Salutation, do Printer) (string){
return do(salutation.name + " " + salutation.greeting)
}
type Printer func(string) string
func createPrintFunction(custom string) Printer {
return func(s string) string {
return s
}
}
func pluralSightModule1Closures1(w http.ResponseWriter, r *http.Request) {
var s = Salutation{"Joe", "Hello"}
res := Greet2(s, createPrintFunction("!!!"))
w.Header().Set("Content-Type", "application/json")
w.Write([]byte (res))
}

Standard lib flag.intValue does not have String method

func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
f.Var(newIntValue(value, p), name, usage)
}
func (f *FlagSet) Var(value Value, name string, usage string) {
flag := &Flag{name, usage, value, value.String()}
// ...
}
func newIntValue(val int, p *int) *intValue {
*p = val
return (*intValue)(p)
}
type intValue int
type Value interface {
String() string
Set(string) error
}
I read the flag.Int source code, and found:
Standard lib flag.intValue does not implements String and Set method, I doesn't found them, how var value Value = &intValue works?
(Sorry, my native language is not English.)

Dynamic function call in Go

I'm trying to dynamically call functions returning different types of struct.
For example, let's take the following code.
struct A {
Name string
Value int
}
struct B {
Name1 string
Name2 string
Value float
}
func doA() (A) {
// some code returning A
}
func doB() (B) {
// some code returning B
}
I would like to pass either the function doA or doB as an argument to a generic function that would execute the function and JSON-encode the result. Like the following:
func Generic(w io.Writer, fn func() (interface {}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
But when I do:
Generic(w, doA)
I get the following error:
cannot use doA (type func() (A)) as type func() (interface {})
Is there a way to achieve this dynamic call?
First, let me remark that func() (interface{}) means the same thing as func() interface{}, so I'll use the shorter form.
Passing a function of type func() interface{}
You can write a generic function that takes a func() interface{} argument as long as the function that you pass to it has type func() interface{}, like this:
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() interface{} {
return &A{"Cats", 10}
}
func doB() interface{} {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn func() interface{}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
You can try out this code in a live playground:
http://play.golang.org/p/JJeww9zNhE
Passing a function as an argument of type interface{}
If you want to write functions doA and doB that return concretely typed values, you can pass the chosen function as an argument of type interface{}. Then you can use the reflect package to make a func() interface{} at run-time:
func Generic(w io.Writer, f interface{}) {
fnValue := reflect.ValueOf(f) // Make a concrete value.
arguments := []reflect.Value{} // Make an empty argument list.
fnResults := fnValue.Call(arguments) // Assume we have a function. Call it.
result := fnResults[0].Interface() // Get the first result as interface{}.
json.NewEncoder(w).Encode(result) // JSON-encode the result.
}
More concisely:
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
Complete program:
package main
import (
"encoding/json"
"io"
"os"
"reflect"
)
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() *A {
return &A{"Cats", 10}
}
func doB() *B {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
func main() {
Generic(os.Stdout, doA)
Generic(os.Stdout, doB)
}
Live playground:
http://play.golang.org/p/9M5Gr2HDRN
Your return signature is different for these functions:
fn func() (interface {}) vs. func doA() (A) and func doB() (B)
You are getting a compiler error because you are passing a function with a different signature into your Generic function. To address this issue you can change your functions to return interface{}.
This is an example of how to do that, I am using anonymous structs and printing the return value out rather than serializing them but this applies just the same to your example:
package main
import "fmt"
func doA() interface{} {
return struct {
Name string
Value int
}{
"something",
5,
}
}
func doB() interface{} {
return struct {
Name1 string
Name2 string
Value float64
}{
"something",
"or other",
5.3,
}
}
func main() {
fmt.Println("Hello, playground", doA(), doB())
}
Experiment with this in the Go Playground: http://play.golang.org/p/orrJw2XMW8

Resources