Is it possible to conditionally implement the comma ok idiom in go, like map lookup? [duplicate] - go

This question already has answers here:
Return map like 'ok' in Golang on normal functions
(2 answers)
Closed 6 months ago.
In golang, you can fetch a key from a map using the obvious syntax:
someMap := map[string]string{
//... contents
}
value := someMap["key1"]
// If "key1" exists in someMap, then the value will be returned; else empty string.
Problem: You can't tell missing keys apart from legitimate empty string values
So, you can test for presence using the comma ok idiom
value, ok := someMap["key1"]
if ok {
// we know that "key1" was in the map, even if value is empty string
} else {
// we know that "key1" was NOT in the map
}
What this looks like is that there are two different overloads of the map lookup method, one which returns just a single map value result, and one which returns the (value, bool) result, and the compiler seems to be selecting the overload based on how many return values you've said you'd like to receive.
This is quite nice, and I was wondering if it was possible to implement this on my own functions?
E.g:
func fetchValue() (string, bool) {
return "", true
}
func testMain() {
// This works fine, as expected
val, ok := fetchValue()
if ok {
fmt.Println(val)
}
// COMPILE ERROR: Assignment count mismatch: 1 = 2.
val2 := fetchValue()
}
// COMPILE ERROR: fetchValue redeclared in this package
func fetchValue() string {
return ""
}
Is this possible? or is it secret special language sauce that only works for the builtin map type and nothing else?

You cannot define your own function that sometimes returns 2 values, sometimes 1.
You can do:
val, ok := fetchValue()
if !ok {
// failure path.
}
or
val, _ := fetchValue()
// not checking for failure.

Related

Passing a []fmt.Stringer parameter to a func [duplicate]

This question already has answers here:
Can I type assert a slice of interface values?
(2 answers)
Closed 3 years ago.
I have a type that implements the stringer interface
// RowID stores the ID of a single row in a table
type RowID []string
// String implements Stringer interface for RowID
func (r RowID) String() string {
return fmt.Sprintf("[%s]", strings.Join(r, ", "))
}
And I have a function that I want to pass a slice of this type (or any other type that implements the Stringer interface) to.
// PrintChanges ...
func PrintChanges(ids []fmt.Stringer) {
for _, id := range ids {
fmt.Println(id)
}
}
However, The go compiler gives me an error:
cannot use rowIDs (type []RowID) as type []fmt.Stringer in argument to PrintChanges
I can pass a RowID to a func that accepts a single fmt.Stringer
func PrintChange(id fmt.Stringer) {
fmt.Println(id)
}
...
PrintChange(RowID{"1", "24"})
But for some reason I am not able to pass a slice of RowID to a func that accepts a slice of fmt.Stringer. What am I missing?
Go Playground
Keep it simple
It is considered okay by professional Go programmers to repeat functions like this for every type, or to have a for loop over every slice you want to print. This is because Go aims to be as easy to read as possible, i.e. a person who reads a chunk of code for the first time should not be asking questions like "which function overload will this function call go to" (common pitfall in C++, Go does not have function overloads). So you can just write in main():
Playground: https://ideone.com/IL3rGR
for _, id := range rowIDs { fmt.Println(id) }
Simple and concise.
Note that fmt.Println(id) does not call your String() function
This is because the fmt library uses the reflect library and hardcodes behavior for the string type, which you are trying to replace. RowID instances are also string instances, the library always prefers string over its type aliases. I would say it is a bug in the library:
Library source: https://golang.org/src/fmt/print.go#L649
// Some types can be done without reflection.
switch f := arg.(type) {
...
case string:
p.fmtString(f, verb)
If you really want to
You can use a function that takes an interface{} and makes a runtime reflect type cast to a slice of Stringers. Note that this means you will not see type mismatches during compilation, only in runtime:
Playground: https://ideone.com/vlrBP9
func castToStringerSlice(iface interface{}) ([]fmt.Stringer, bool /* ok */) {
if reflect.TypeOf(iface).Kind() != reflect.Slice {
return nil, false
}
v := reflect.ValueOf(iface)
stringers := make([]fmt.Stringer, v.Len())
for i := 0; i < v.Len(); i++ {
stringers[i] = v.Index(i)
}
return stringers, true
}
func PrintChanges(iface_ids interface{}) {
ids, ok := castToStringerSlice(iface_ids)
if !ok {
log.Fatal(errors.New("the argument to PrintChanges must be a slice of Stringers"))
}
for _, id := range ids {
fmt.Println(id)
}
}
Resources:
Go documentation: Why does Go not support overloading of methods and operators?
Go documentation: Why does Go not have generic types?
Stack Overflow: Express function that takes any slice
Stack Overflow: Range over interface{} which stores a slice
Go documentation: Package reflect

how to assign only on return value of a function to field of an struct in golang? [duplicate]

This question already has answers here:
Multiple values in single-value context
(6 answers)
Closed 5 years ago.
let's say we have a struct like this:
type Data struct {
a int
}
and we want to get a single return value of a function that returns multiple values and assign it to an object of Data, for example
data := Data {
a: strconv.Atoi("1000")
}
the code above does not work because Atoi returns two value, a number and an error, so we need to handle the extra value (error) somehow, but in my case, I do not need to evaluate error value and it is not possible to dismiss it using _ keyword.
how can I achieve this when initializing a struct, I want to get rid of the error return value
There is no generic way to get just one of returned parameters (Maybe you could implement something with reflect package that returns interface{}).
Other than that it's not good to ignore errors. If you are sure that there's no error implement a helper function like this:
func myAtoi(s string) int {
i, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
return i
}
data := Data {
a: myAtoi("1000")
}

Cannot Range Over List Type Interface {} In Function Using Go

Cannot Range Over List Type Interface {} In Function Using Go.
for me is important then i execute for in a function.
How can fix?
package main
import (
"fmt"
)
type MyBoxItem struct {
Name string
}
type MyBox struct {
Items []MyBoxItem
}
func (box *MyBox) AddItem(item MyBoxItem) []MyBoxItem {
box.Items = append(box.Items, item)
return box.Items
}
func PrintCustomArray(list interface{}) interface{} {
//items := reflect.ValueOf(list)
for _, v := range list {
fmt.Println(v.Key,v.Value)
}
return 0
}
func main() {
items := []MyBoxItem{}
item := MyBoxItem{Name: "Test Item 1"}
box := MyBox{items}
box.AddItem(item)
fmt.Println((box.Items))
PrintCustomArray(box.Items)
}
https://play.golang.org/p/ZcIBLMliq3
Error : cannot range over list (type interface {})
How can fix?
Note
The answer below describes, in broad strokes, 2 possible approaches: using interfaces, and using specific types. The approach focusing on interfaces is mentioned for completeness sake. IMHO, the case you've presented is not a viable use-case for interfaces.
Below, you'll find a link to a playground example that uses both techniques. It should be apparent to anyone that the interface approach is too cumbersome if for this specific case.
Quite apart from the fact that you don't really seem to be too familiar with how loops work in go (v.Key and v.Value are non-existent fields for example), I'll attempt to answer your question.
You are passing a list to your function, sure enough, but it's being handled as an interface{} type. That means your function accepts, essentially, any value as an argument. You can't simply iterate over them.
What you can do is use type assertions to convert the argument to a slice, then another assertion to use it as another, specific interface:
type Item interface{
key() string
val() string
}
func (i MyBoxItem) key() string {
return i.Key
}
func (i MyBoxItem) val() string {
return i.Value
}
func PrintCustomArray(list interface{}) error {
listSlice, ok := list.([]interface{})
if !ok {
return fmt.Errorf("Argument is not a slice")
}
for _, v := range listSlice {
item, ok := v.(Item)
if !ok {
return fmt.Errorf("element in slice does not implement the Item interface")
}
fmt.Println(item.key(), item.val())
}
return nil
}
But let's be honest, a function like this only works if a slice is passed as an argument. So having that first type assertion in there makes no sense whatsoever. At the very least, changing the function to something like this makes a lot more sense:
func PrintCustomArray(list []interface{})
Then, because we're not expecting an array as such, but rather a slice, the name should be changed to PrintCustomSlice.
Lastly, because we're using the same type assertion for every value in the slice, we might as well change the function even more:
// at this point, we'll always return 0, which is pointless
// just don't return anything
func PrintCustomSlice(list []Item) {
for _, v := range list {
fmt.Println(v.key(), v.val())
}
}
The advantages of a function like this is that it can still handle multiple types (all you have to do is implement the interface). You don't need any kind of expensive operations (like reflection), or type assertions.
Type assertions are very useful, but in a case like this, they merely serve to hide problems that would otherwise have resulted in a compile-time error. Go's interface{} type is a very useful thing, but you seem to be using it to get around the type system. If that's what you want to achieve, why use a typed language in the first place?
Some closing thoughts/remarks: If your function is only going to be used to iterate over specific "thing", you don't need the interfaces at all, simply specify the type you're expecting to be passed to the function in the first place. In this case that would be:
func PrintCustomSlice(list []MyBoxItem) {
for _, v := range list {
fmt.Println(v.Key, v.Value)
}
}
Another thing that I've noticed is that you seem to be exporting everything (all functions, types, and fields start with a capital letter). This, in go, is considered bad form. Only export what needs to be public. In the main package, that usually means you're hardly export anything.
Lastly, as I mentioned at the start: you don't seem to have a firm grasp on the basics just yet. I'd strongly recommend you go through the interactive tour. It covers the basics nicely, but shows you the features of the language at a decent pace. It doesn't take long, and is well worth taking a couple of hours to complete
Playground demo
It's possible to implement PrintCustomArray using the reflect package, but most experienced Go programmers will write a simple for loop:
for _, i := range box.Items {
fmt.Println("Name:", i.Name)
}
https://play.golang.org/p/RhubiCpry0
You can also encapsulate it in a function:
func PrintCustomArray(items []MyBoxItem) {
for _, i := range items {
fmt.Println("Name:", i.Name)
}
}
https://play.golang.org/p/c4EPQIx1AH
Here since you are returning box.Items from AddItem(), Items is of the type []MyBoxItem , so list should be of type []MyBoxItem .Moreover you are returning 0 in PrintCustomArray and the return type you have set is {}interface.
func PrintCustomArray(list []MyBoxItem) {
//items := reflect.ValueOf(list)
for i, v := range list {
fmt.Println(i, v)
}
//return 0
}
Again, MyBoxItem struct has only one variable named Name so v.key v.value won't make any sense.
This is what the proper code should look like https://play.golang.org/p/ILoUwEWv6Y .
You need to clear your understanding about interfaces in go. This might help https://golang.org/doc/effective_go.html#interfaces_and_types .

Pass a result from multi-returing function to another one taking only one argument in Go

Is it possible to pass a result form function which returns multiple values directly to function which accepts only one? Example:
func MarshallCommandMap(mapToMarshall map[string]string) string {
return string(json.Marshal(mapToMarshall))
}
The example above will cause compilation error:multiple-value json.Marshal() in single-value context. I know it is possible to get same result with additional variable:
func MarshallCommandMap(mapToMarshall map[string]string) string {
marshaledBytes, marshalingError := json.Marshal(mapToMarshall)
if (marshalingError != nil) {
panic(marshalingError)
}
return string(marshaledBytes)
}
But is it possible to pass only first value direclty without any variable?
I think you mean doing something like python's tuple unpacking.
Unfortunately this is not possible in Go (AFAIK).
No you can't, however 2 things with your code.
Shouldn't panic, either return an error or return an empty string.
You can make it shorter.
Example :
func MarshallCommandMap(mapToMarshall map[string]string) string {
js, _ := json.Marshal(mapToMarshall) //ignore the error
return string(js)
}

Writing generic data access functions in Go

I'm writing code that allows data access from a database. However, I find myself repeating the same code for similar types and fields. How can I write generic functions for the same?
e.g. what I want to achieve ...
type Person{FirstName string}
type Company{Industry string}
getItems(typ string, field string, val string) ([]interface{}) {
...
}
var persons []Person
persons = getItems("Person", "FirstName", "John")
var companies []Company
cs = getItems("Company", "Industry", "Software")
So you're definitely on the right track with the idea of returning a slice of nil interface types. However, you're going to run into problems when you try accessing specific members or calling specific methods, because you're not going to know what type you're looking for. This is where type assertions are going to come in very handy. To extend your code a bit:
getPerson(typ string, field string, val string) []Person {
slice := getItems(typ, field, val)
output := make([]Person, 0)
i := 0
for _, item := range slice {
// Type assertion!
thing, ok := item.(Person)
if ok {
output = append(output, thing)
i++
}
}
return output
}
So what that does is it performs a generic search, and then weeds out only those items which are of the correct type. Specifically, the type assertion:
thing, ok := item.(Person)
checks to see if the variable item is of type Person, and if it is, it returns the value and true, otherwise it returns nil and false (thus checking ok tells us if the assertion succeeded).
You can actually, if you want, take this a step further, and define the getItems() function in terms of another boolean function. Basically the idea would be to have getItems() run the function pass it on each element in the database and only add that element to the results if running the function on the element returns true:
getItem(critera func(interface{})bool) []interface{} {
output := make([]interface{}, 0)
foreach _, item := range database {
if criteria(item) {
output = append(output, item)
}
}
}
(honestly, if it were me, I'd do a hybrid of the two which accepts a criteria function but also accepts the field and value strings)
joshlf13 has a great answer. I'd expand a little on it though to maintain some additional type safety. instead of a critera function I would use a collector function.
// typed output array no interfaces
output := []string{}
// collector that populates our output array as needed
func collect(i interface{}) {
// The only non typesafe part of the program is limited to this function
if val, ok := i.(string); ok {
output = append(output, val)
}
}
// getItem uses the collector
func getItem(collect func(interface{})) {
foreach _, item := range database {
collect(item)
}
}
getItem(collect) // perform our get and populate the output array from above.
This has the benefit of not requiring you to loop through your interface{} slice after a call to getItems and do yet another cast.

Resources