How do you create a slice of functions with different signatures? - go

How do you create a slice of functions with different signatures? I tried the code below but its feels hack-ish. Do we just bite the bullet and use a slice interface{}?
package main
import (
"fmt"
)
type OneParams func(string) string
type TwoParams func(string, string) string
type ThreeParams func(string, string, string) string
func (o OneParams) Union() string {
return "Single string"
}
func (t TwoParams) Union() string {
return "Double string"
}
func (t ThreeParams) Union() string {
return "Triple string"
}
type Functions interface {
Union() string
}
func Single(str string) string {
return str
}
func Double(str1 string, str2 string) string {
return str1 + " " + str2
}
func Triple(str1 string, str2 string, str3 string) string {
return str1 + " " + str2 + " " + str3
}
func main() {
fmt.Println("Slice Of Functions Program!\n\n")
fSlice := []Functions{
OneParams(Single),
TwoParams(Double),
ThreeParams(Triple),
}
for _, value := range fSlice {
switch t := value.(type) {
case OneParams:
fmt.Printf("One: %s\n", t("one"))
case TwoParams:
fmt.Printf("Two: %s\n", t("one", "two"))
case ThreeParams:
fmt.Printf("Three: %s\n", t("one", "two", "three"))
default:
fmt.Println("Huh! What's that?")
}
}
fmt.Println("\n\n")
}
Is this just a case of trying to do too much with Go?

Please check it, I don't know if it what you want. Because I don't know what are you exactly want.
package main
import (
"fmt"
"reflect"
)
func A() {
fmt.Println("A")
}
func B(A int) {
fmt.Println("B", A)
}
func C(A string, B float32) {
fmt.Println("C", A, B)
}
func main() {
f := []interface{}{A, B, C}
f[0].(func())()
f[1].(func(int))(15)
f[2].(func(string, float32))("TEST", 90)
fmt.Println("\n******* another thing ******")
for a, v := range f {
v := reflect.TypeOf(v)
fmt.Println("#######", a)
fmt.Println("num param :", v.NumIn())
for i := 0; i < v.NumIn(); i++ {
fmt.Println("param :", i, "type is ", v.In(i))
}
}
}
Check on Go Playground
Here I have another example calling using reflect
package main
import (
"fmt"
"reflect"
)
func A() {
fmt.Println("A")
}
func B(A int) {
fmt.Println("B", A)
}
func C(A string, B float32) {
fmt.Println("C", A, B)
}
func main() {
f := []interface{}{A, B, C}
f[0].(func())()
f[1].(func(int))(15)
f[2].(func(string, float32))("TEST", 90)
fmt.Println("\n******* calling with reflect ******")
for a, v := range f {
v := reflect.TypeOf(v)
//calling the function from reflect
val := reflect.ValueOf(f[a])
params := make([]reflect.Value, v.NumIn())
if v.NumIn() == 1 {
params[0] = reflect.ValueOf(1564)
} else if v.NumIn() == 2 {
params[0] = reflect.ValueOf("Test FROM reflect")
params[1] = reflect.ValueOf(float32(123456))
}
val.Call(params)
}
}
Check on Go Playground

depends on what the different you need. upon your example, we could use variadic.
package main
import(
"fmt"
"strings"
)
func foo(ss ...string) string{
return strings.Join(ss, " ")
}
func main(){
fmt.Println(foo("one"))
fmt.Println(foo("one", "two"))
fmt.Println(foo("one", "two", "three"))
}

Related

How to transform any string in struct field name like

I would like to know if there is a native way to transform strings like:
a.string
a-string
a_string
a string
In a string that follows the convention for public field members of structs, in Go.
The idea is to write a function that accepts a string and try to get the value of the field, even if the passed string is not using the PascalCase convention, example:
type MyStruct struct {
Debug bool
AString bool
SomethingMoreComplex
}
var myStruct MyStruct
func GetField(s string) reflect.Value {
v := reflect.ValueOf(myStruct)
return v.FieldByName(s)
}
function main() {
GetField("debug")
GetField("a.string")
GetField("a-string")
GetField("a_string")
GetField("-a.string")
GetField("something-more-complex")
}
I was using the strcase package, but it only works for ASCII.
By the magic of regular expressions
https://goplay.space/#xHfxG249CsH
package main
import (
"fmt"
"regexp"
"strings"
)
func ConvertFieldName(s string) string {
r := regexp.MustCompile("(\\b|-|_|\\.)[a-z]")
return r.ReplaceAllStringFunc(s, func(t string) string {
if len(t) == 1 {
return strings.ToUpper(t)
} else {
return strings.ToUpper(string(t[1]))
}
})
}
func main() {
fmt.Println(ConvertFieldName("debug"))
fmt.Println(ConvertFieldName("a.string"))
fmt.Println(ConvertFieldName("a-string"))
fmt.Println(ConvertFieldName("a_string"))
fmt.Println(ConvertFieldName("-a.string"))
fmt.Println(ConvertFieldName("something-more-complex"))
}
Outputs
Debug
AString
AString
AString
AString
SomethingMoreComplex
package main
import (
"fmt"
"reflect"
)
type MyStruct struct {
Debug bool
AString bool
}
var myStruct MyStruct
func GetField(s string) (reflect.Value, error) {
t := reflect.TypeOf(myStruct)
v := reflect.ValueOf(myStruct)
for fieldIndex := 0; fieldIndex < v.NumField(); fieldIndex++ {
if t.Field(fieldIndex).Name == s {
return v.Field(fieldIndex), nil
}
}
return reflect.Value{}, fmt.Errorf("%s not exist", s)
}
func main() {
var v reflect.Value
var err error
v, err = GetField("Debug")
fmt.Println(v, err)
v, err = GetField("debug")
fmt.Println(v, err)
}
the other way, you can try define your own field's tag, like json tag

fmt format specifier to print only field with non-zero value

Consider this code:
package main
import (
"fmt"
)
type myStruct struct {
a string
b int
c bool
}
func main() {
s := myStruct{
c: true,
}
fmt.Printf("%v", s)
// print { 0 true}
fmt.Printf("%+v", s)
// print {a: b:0 c:true}
}
Is there a fmt format specifier to print only fields with non-zero value?
For example, with the code above, how can I print only
{c:true}
because a == "" and b == 0?
There is no built-in format verb that causes zero values to be omitted.
Here are some options.
fmt.Stringer
You can hard-code the string format for your type by implementing fmt.Stringer:
package main
import (
"fmt"
"strings"
)
type myStruct struct {
a string
b int
c bool
}
func (s myStruct) String() string {
var fields []string
if s.a != "" {
fields = append(fields, fmt.Sprintf("a:%q", s.a))
}
if s.b != 0 {
fields = append(fields, fmt.Sprintf("b:%d", s.b))
}
if s.c {
fields = append(fields, fmt.Sprintf("c:%t", s.c))
}
return fmt.Sprintf("{%s}", strings.Join(fields, ","))
}
func main() {
s := myStruct{a: "foo"}
fmt.Println(s)
}
Output:
{a:"foo"}
https://play.golang.org/p/Dw7F4Ua0Eyq
Reflection
You can use reflection to build something that will work with any struct, but it is perhaps more hassle than it is worth. Example omitted.
JSON
Another alternative is to marshal it to JSON, which handles the reflection part and has support for omitting zero values. Example:
package main
import (
"encoding/json"
"log"
"os"
)
type myStruct struct {
A string `json:",omitempty"`
B int `json:",omitempty"`
C bool `json:",omitempty"`
}
func main() {
s := myStruct{A: "foo"}
if err := json.NewEncoder(os.Stdout).Encode(s); err != nil {
log.Fatal(err)
}
}
Output:
{"A":"foo"}
https://play.golang.org/p/NcckEBNdnW6
JSON with unexported fields
If you prefer to keep the original struct as-is; you can define a custom marshaller with an anonymous struct. Note however that the struct format is then duplicated in the MarshalJSON method which adds a bit of complexity:
package main
import (
"encoding/json"
"log"
"os"
)
type myStruct struct {
a string
b int
c bool
}
func (s myStruct) MarshalJSON() ([]byte, error) {
return json.Marshal(
struct {
A string `json:"a,omitempty"`
B int `json:"b,omitempty"`
C bool `json:"c,omitempty"`
}{
A: s.a,
B: s.b,
C: s.c,
},
)
}
func main() {
s := myStruct{a: "foo"}
if err := json.NewEncoder(os.Stdout).Encode(s); err != nil {
log.Fatal(err)
}
}
Output:
{"a":"foo"}
https://play.golang.org/p/qsCKUNeFLpw
JSON with unexported fields + fmt.Stringer
If you want, you can again implement fmt.Stringer, which fmt.Printf and friends will pick up:
package main
import (
"encoding/json"
"fmt"
)
type myStruct struct {
a string
b int
c bool
}
func (s myStruct) MarshalJSON() ([]byte, error) {
return json.Marshal(
struct {
A string `json:"a,omitempty"`
B int `json:"b,omitempty"`
C bool `json:"c,omitempty"`
}{
A: s.a,
B: s.b,
C: s.c,
},
)
}
func (s myStruct) String() string {
j, err := json.Marshal(s)
if err != nil {
return ""
}
return string(j)
}
func main() {
s := myStruct{a: "foo"}
fmt.Println(s)
}
Output:
{"a":"foo"}
https://play.golang.org/p/TPDoLOTAVJo

swap two strings (Golang)

I am currently learning Golang, and i decided to write few simple algorithm for learning the syntax. i hope it's not already answers but i didn't found it ..
I have a problem for swapping string
func swap(str1, str2 string) {
/*
* Also possible :
* str1, str2 = str2, str1
*/
// str1, str2 = str2, str1
tmp := str1
str1 = str2
str2 = tmp
}
func main() {
a := "World !"
b := "Hello"
swap(a, b)
fmt.Printf("a=%s\nb=%s\n", a, b)
}
Why this code didn't work ?
Swapping str1 and str2 doesn't change a and b, because they are copies of a and b. Use pointers:
func swap(str1, str2 *string) {
*str1, *str2 = *str2, *str1
}
func main() {
a := "salut"
b := "les gens"
swap(&a, &b)
fmt.Printf("a=%s\nb=%s\n", a, b)
}
http://play.golang.org/p/Qw0t5I-XGT
This will be the idiomatic way.
package main
import "fmt"
func swap(a, b string)(string, string) {
return b, a
}
func main() {
f, s := swap("world" , "hello")
fmt.Println(f, s)
}
Built-in types as function arguments are passed by value, but if the elements for dereference will modify the original value, such as slice, map. e.g.
package main
import (
"bytes"
"fmt"
"strings"
)
func f_1(a int) {
a = 2
}
func f_1_1(a *int) {
*a = 2
}
func f_2(s string) {
s = "cba"
}
func f_2_1(s *string) {
*s = "cba"
}
func f_3(v []string) {
v[0] = "haha"
}
func f_3_1(v []string) {
v = nil
}
func f_3_2(v *[]string) {
*v = nil
}
func f_4(m map[int]int) {
m[1] = 3
m[3] = 1
}
func f_4_1(m map[int]int) {
m = nil
}
func f_4_2(m *map[int]int) {
*m = nil
}
func f_5(b []byte) {
b[0] = 0x40
}
func f_5_1(b []byte) {
b = bytes.Replace(b, []byte("1"), []byte("a"), -1)
}
func f_5_2(b *[]byte) {
*b = bytes.Replace(*b, []byte("1"), []byte("a"), -1)
}
type why struct {
s []string
}
func (ss why) SetV(s []string) {
ss.s = s
}
func (ss *why) SetP(s []string) {
ss.s = s
}
func (ss why) String() string {
return strings.Join(ss.s, ",")
}
func main() {
a := 1
s := "abc"
v := []string{"sd", "aa"}
m := map[int]int{1: 1, 2: 2, 3: 3}
f_1(a)
f_2(s)
f_3(v)
f_4(m)
fmt.Printf("%d,%s,%v,%v\n", a, s, v, m)
f_3_1(v)
f_4_1(m)
fmt.Printf("%d,%s,%v,%v\n", a, s, v, m)
f_1_1(&a)
f_2_1(&s)
f_3_2(&v)
f_4_2(&m)
fmt.Printf("%d,%s,%v,%v\n", a, s, v, m)
b := []byte("12145178")
f_5(b)
fmt.Printf("%s\n", b)
f_5_1(b)
fmt.Printf("%s\n", b)
f_5_2(&b)
fmt.Printf("%s\n", b)
ss := &why{}
ss.SetV([]string{"abc", "efg"})
fmt.Println(ss)
ss.SetP([]string{"abc", "efg"})
fmt.Println(ss)
}
you can write as that:
a := "hello"
b := "world"
a, b = b, a
package main
import "fmt"
func swap(a,b string)(string, string){
return b,a
}
func main(){
fmt.Println(swap("Lang","Go"))
}

How to recursively join a string to an array of type string in golang

I am struggling with this for quite some time. I basically want to create a function that recursively join a string to an array.
Like this :
join ", " ["one","two","three"]
should look like this "one, two, three"
There is already Join function in strings module. But it's not recursive, if you need recursive you can make it like this:
package main
import "fmt"
func join_helper(splitter string, arrOfStrings []string, res string) string {
if len(arrOfStrings) == 0 {
return res
}
if len(arrOfStrings) == 1 {
return join_helper(splitter, arrOfStrings[1:], res + arrOfStrings[0])
}
return join_helper(splitter, arrOfStrings[1:], res + arrOfStrings[0] + splitter)
}
func join(splitter string, arrOfStrings []string) string {
return join_helper(splitter, arrOfStrings, "")
}
func main(){
fmt.Println(join(",", []string{"a", "b", "c", "d"}))
}
Something like this
package main
import (
"fmt"
"strings"
)
func flatJoin(sep string, args ...interface{}) string {
values := make([]string, 0)
for _, item := range args {
switch v := item.(type) {
case string:
values = append(values, v)
case []string:
values = append(values, v...)
case fmt.Stringer:
values = append(values, v.String())
default:
values = append(values, fmt.Sprintf("%v", v))
}
}
return strings.Join(values, sep)
}
func main() {
fmt.Println(flatJoin(", ", "basic", "other", []string{"here", "more", "inner"}))
}
http://play.golang.org/p/yY6YnZZAak
This supports only one level of flattening, but you can customize the recursion on your switch statement depending on what you are expecting.

ToString() function in Go

The strings.Join function takes slices of strings only:
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))
But it would be nice to be able to pass arbitrary objects which implement a ToString() function.
type ToStringConverter interface {
ToString() string
}
Is there something like this in Go or do I have to decorate existing types like int with ToString methods and write a wrapper around strings.Join?
func Join(a []ToStringConverter, sep string) string
Attach a String() string method to any named type and enjoy any custom "ToString" functionality:
package main
import "fmt"
type bin int
func (b bin) String() string {
return fmt.Sprintf("%b", b)
}
func main() {
fmt.Println(bin(42))
}
Playground: http://play.golang.org/p/Azql7_pDAA
Output
101010
When you have own struct, you could have own convert-to-string function.
package main
import (
"fmt"
)
type Color struct {
Red int `json:"red"`
Green int `json:"green"`
Blue int `json:"blue"`
}
func (c Color) String() string {
return fmt.Sprintf("[%d, %d, %d]", c.Red, c.Green, c.Blue)
}
func main() {
c := Color{Red: 123, Green: 11, Blue: 34}
fmt.Println(c) //[123, 11, 34]
}
Another example with a struct :
package types
import "fmt"
type MyType struct {
Id int
Name string
}
func (t MyType) String() string {
return fmt.Sprintf(
"[%d : %s]",
t.Id,
t.Name)
}
Be careful when using it,
concatenation with '+' doesn't compile :
t := types.MyType{ 12, "Blabla" }
fmt.Println(t) // OK
fmt.Printf("t : %s \n", t) // OK
//fmt.Println("t : " + t) // Compiler error !!!
fmt.Println("t : " + t.String()) // OK if calling the function explicitly
This works well
package main
import "fmt"
type Person struct {
fname, sname string
address string
}
func (p *Person) String() string {
s:= fmt.Sprintf("\n %s %s lives at %s \n", p.fname, p.sname, p.address)
return s
}
func main(){
alex := &Person{"Alex", "Smith", "33 McArthur Bvd"}
fmt.Println(alex)
}
Output:
Alex Smith lives at 33 McArthur Bvd
If you have a fixed set of possible types for elements that could be converted, then you can define conversion functions for each, and a general conversion function that uses reflection to test the actual type of an element and call the relevant function for that element, eg:
func ToStringint(x int) string {
return strconv.Itoa(x)
}
func ToStringlong(x int64) string {
return strconv.FormatInt(x,10)
}
func ToStringdouble(x float64) string {
return fmt.Sprintf("%f", x)
}
func ToStringboolean(x bool) string {
if x {
return "true"
}
return "false"
}
func ToStringOclAny(x interface{}) string {
if reflect.TypeOf(x) == TYPEint {
return strconv.Itoa(x.(int))
}
if reflect.TypeOf(x) == TYPEdouble {
return fmt.Sprintf("%f", x.(float64))
}
if reflect.TypeOf(x) == TYPElong {
return strconv.FormatInt(x.(int64),10)
}
if reflect.TypeOf(x) == TYPEString {
return x.(string)
}
if reflect.TypeOf(x) == TYPEboolean {
return ToStringboolean(x.(bool))
}
if reflect.TypeOf(x) == TYPESequence {
return ToStringSequence(x.(*list.List))
}
if reflect.TypeOf(x) == TYPEMap {
return ToStringMap(x.(map[interface{}]interface{}))
}
return ""
}
func ToStringSequence(col *list.List) string {
res := "Sequence{"
for e := col.Front(); e != nil; e = e.Next() {
res = res + ToStringOclAny(e.Value)
if e.Next() != nil {
res = res + ", "
}
}
return res + "}"
}
func ToStringSet(col *list.List) string {
res := "Set{"
for e := col.Front(); e != nil; e = e.Next() {
res = res + ToStringOclAny(e.Value)
if e.Next() != nil {
res = res + ", "
}
}
return res + "}"
}
func ToStringMap(m map[interface{}]interface{}) string {
res := "Map{"
for i, v := range m {
res = res + ToStringOclAny(i) + " |-> " + ToStringOclAny(v) + " "
}
return res + "}"
}
Here is a simple way to handle this:
package main
import (
"fat"
"strconv"
)
type Person struct {
firstName, lastName string
age int
}
func (p Person) GetFullName() string {
return p.firstName + " " + p.lastName
}
func (p Person) GetAge() int {
return p.age
}
func (p Person) GetAgeAsString() string {
return strconv.Itoa(p.age)
}
func main() {
p := Person {"John", "Doe", 21}
fmt.Println(p.GetFullName())
fmt.Println(p.GetAgeAsString())
}
Output:
"John Doe"
"21"
I prefer something like the following:
type StringRef []byte
func (s StringRef) String() string {
return string(s[:])
}
…
// rather silly example, but ...
fmt.Printf("foo=%s\n",StringRef("bar"))

Resources