Standard lib flag.intValue does not have String method - go

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.)

Related

How to display student list in this program in Go language?

package main
import (
"fmt"
)
type Student struct {
rollnumber int
name string
address string
}
func NewStudent(rollno int, name string, address string) *Student {
s := new(Student)
s.rollnumber = rollno
s.name = name
s.address = address
return s
}
type StudentList struct {
list []*Student
}
func (ls *StudentList) CreateStudent(rollno int, name string, address string) *Student {
st := NewStudent(rollno, name, address)
ls.list = append(ls.list, st)
return st
}
func main() {
student := new(StudentList)
student.CreateStudent(24, "Asim", "AAAAAA")
student.CreateStudent(24, "Naveed", "BBBBBB")
fmt.Println(student)
}
/* When I run this program it gives addresses in output instead of the values I stored kindly check and let me know how can I display the actual data. I am a newbie in Go*/
You can remove the pointer by dereferencing it:
fmt.Println(*student)
But your StudentList.list is an array of pointers to students so you need to derefence those too. My 2 cents, don't use pointers unless you have good reason to.
See your code slightly modified:
https://go.dev/play/p/PkNkUF0EFt7
You can implement Stringer on struct StudentList to modify the output on fmt pkg.
This is the example:
...
type StudentList struct {
list []*Student
}
...
func (ls StudentList) String() string {
var b strings.Builder
for _, v := range ls.list {
fmt.Fprintf(&b, "%+v\n", *v)
}
return b.String()
}
playground

Converting Slice of custom type to slice of string

I have multiple structs like bellow
type Person struct {
first string
last string
age int
}
type Product struct {
ProductID int
Name string
Description string
Price float64
}
I want a function that will take a slice of any type as the first argument and a function as a second argument that it will use to call with each element of the slice to construct a string slice and will return that string slice. Something like map() in Typescript/scala or select() in C#.
Since Go doesn't have generics, "any type" can only mean interface{}. You can have something like this:
func ToStringSlice(arr []interface{}, convert func(interface{}) string) []string {
ret := []string{}
for _, elem := range arr {
ret = append(ret, convert(elem))
}
return ret
}
Then you can basically inject any conversion function you want. e.g.
fmt.Println(ToStringSlice([]interface{}{1, 2, "foo", "bar"},
func(x interface{}) string {
return fmt.Sprint(x)
}))
And since string conversions can go bad, I'd also add error checking:
// Define the function with an error return.
type Stringifier func(interface{}) (string, error)
func ToStringSlice(arr []interface{}, convert Stringifier) ([]string, error) {
ret := []string{}
for _, elem := range arr {
if s, e := convert(elem); e != nil {
return nil, e
} else {
ret = append(ret, s)
}
}
return ret, nil
}
one solution involves fmt.Stringer
package main
import (
"fmt"
)
func main() {
items := []fmt.Stringer{Product{ProductID: 1}, Person{first: "first"}}
var res []string
for _, i := range items {
res = append(res, i.String())
}
fmt.Println(res)
}
type Person struct {
first string
last string
age int
}
func (p Person) String() string { return p.first }
type Product struct {
ProductID int
Name string
Description string
Price float64
}
func (p Product) String() string { return fmt.Sprint(p.ProductID) }
That's a typical use case for an interface. Luckily enough the interface you need already exists as fmt.Stringer (https://golang.org/pkg/fmt/#Stringer):
Have a look at https://play.golang.org/p/d1sNPLKhNCU...
First your structs are required to implement the Stringer interface. This is done by simply adding a menthode String(), for example:
type Product struct {
ProductID int
Name string
Description string
Price float64
}
func (p Product) String() string {
return fmt.Sprintf("%d %s", p.ProductID, p.Name)
}
Now your Product is also a Stringer and can be Therefore be passed in any function that accepts Stringers:
func AsStringSlice(in []fmt.Stringer) []string {
out := []string{}
for _, i := range in {
out = append(out, i.String())
}
return out
}
Since "interface{} says nothing" (https://go-proverbs.github.io/) I would recommend to use interface{} as rarely as possible. This is achieved in this approach. Also you can avoid reflection that way.
On the other hand you have to be able to manage the structs, eg. implement the String function. If thats not possible because the Types come from a dependency consider wrapping them:
type MyTypeWithStringer package.ForeinTypeWithoutStringer
func(t MyTypeWithStringer) String() string {
// ...
}
This is a solution that fits me best
type Person struct {
first string
last string
age int
}
type Product struct {
ProductID int
Name string
Description string
Price float64
}
func mapToStringSlice(slice interface{}, mapFunc func(interface{}) string) []string {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("mapToStringSlice() given a non-slice type")
}
ret := make([]string, s.Len())
for i:=0; i<s.Len(); i++ {
ret[i] = mapFunc(s.Index(i).Interface())
}
return ret
}
func main() {
persons := []Person{{
first: "A",
last: "g",
age: 20,
},{
first: "B",
last: "r",
age: 40,
},{
first: "C",
last: "",
age: 0,
}}
products := []Product{Product{ProductID: 1}, Product{ProductID: 2}}
personFirstNames := mapToStringSlice(persons, func(input interface{}) string {
return input.(Person).first
})
productIDs := mapToStringSlice(products, func(input interface{}) string {
return input.(Product).ProductID
})
}

Shouldn't the method explicitly contract with the signature of interface?

I am new with the golang, I am not quite understand why the below demo program could be executed successfully,
type fake interface {
getAge(valueInt int, valStr string) (age int, name string, err error)
}
type Foo struct {
name string
}
func (b *Foo) getAge(valueInt int, valStr string) (age int, retErr error) {
age = valueInt
return age, nil
}
func main() {
inst := &Foo{name:"foo"}
value, _ := inst.getAge(2, "foo")
fmt.Println(value)
}
The interface wants to return three value, but the method getAge only return two, but it still works. How to understand this behavior in golang?
Thanks!
Foo doesn't implement fake. This is apparent if you extend your code sample a bit (try it on the Go playground):
package main
import "fmt"
type fake interface {
getAge(valueInt int, valStr string) (age int, name string, err error)
}
type Foo struct {
name string
}
func (b *Foo) getAge(valueInt int, valStr string) (age int, retErr error) {
age = valueInt
return age, nil
}
func bar(f fake) {
_, name, _ := f.getAge(10, "")
}
func main() {
inst := &Foo{name: "foo"}
value, _ := inst.getAge(2, "foo")
fmt.Println(value)
bar(inst)
}
This produces a compile error that's pretty descriptive:
prog.go:28:5: cannot use inst (type *Foo) as type fake in argument to bar:
*Foo does not implement fake (wrong type for getAge method)
have getAge(int, string) (int, error)
want getAge(int, string) (int, string, error)

Function types in 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).

Set value to inherited field

Look at my code here
package main
import (
"fmt"
)
type iFormatter interface {
SetName(name string)
Format() string
}
type BaseFormatter struct {
name string
}
type Formatter struct {
BaseFormatter
}
func (f Formatter) SetName(name string) {
f.name = name
}
func (f Formatter) Format() string {
return "formatted " + f.name
}
func main() {
var formatters = []iFormatter{Formatter{}}
formatters[0].SetName("KARL")
fmt.Println(formatters[0].Format())
}
I don't understand, why the field "name" is not setted after calling SetName.
Here is the link for playground https://play.golang.org/p/Jkcjv_hFRC.
The SetName() method should be on a pointer, not value. Currently the f is a copy of the formatters[0] and changes to f are not propagated to formatters[0].
The code below should do the trick.
func (f *Formatter) SetName(name string) {
f.name = name
}
...
var formatters = []iFormatter{&Formatter{}}
You don't need to change the Format() method to pointer receiver though in your case it could be better to do it.
See: https://play.golang.org/p/rFmCZesbTB
In your code, changing these two methods like this should make it work as you expect:
func (f *Formatter) SetName(name string) {
f.name = name
}
func (f *Formatter) Format() string {
return "formatted " + f.name
}
and using a pointer as
var formatters = []iFormatter{&Formatter{}}
https://play.golang.org/p/eSX3mXys-a
Basically, using a pointer receiver instead of a value receiver. Using a value receiver works on a copy of the struct instead of the original struct.

Resources