0

Reference Go equivalent of a void pointer in C

this is a demo.

package main

import (
    "fmt"
)

func map_exist(map_val map[string]interface{}, key string) bool {
    _, ok := map_val[key]
    return ok
}

func main() {
    var one map[string][]string
    one["A"] = []string{"a", "b", "c"}
    fmt.Println(map_exist(one, "A"))

    var two map[string]string
    two["B"] = "a"
    fmt.Println(map_exist(two, "B"))
}

run result:

./main.go:15: cannot use one (type map[string][]string) as type map[string]interface {} in argument to map_exist

./main.go:19: cannot use two (type map[string]string) as type map[string]interface {} in argument to map_exist

I can not find a data structure to be able to contain any type .

Community
  • 1
  • 1
soapbar
  • 2,411
  • 4
  • 18
  • 24

2 Answers2

2

Go does not support parametric polymorphism. What you're trying to do is only possible with reflection which will be much longer and more error prone than just using the _, ok := m[key] form. Usually you would write it like so:

if _, ok := m[key]; ok {
    // do something conditionally.
}
Logiraptor
  • 1,496
  • 10
  • 14
2

It's true that interface{} is kind of like C's void *, but you can't implicitly convert a map[string]string into a map[string]interface{}. The key is to define your map objects at their declaration as map[string]interface{} objects. Unfortunately, you cannot assign new values to such a map, since Go can't know how much memory to allocate for each instance.

func main() {
    one := map[string]interface{} {
        "A": []string{"a", "b", "c"},
    }
    fmt.Println(map_exist(one, "A"))

    two := map[string]interface{} {
        "B": "a",
    }
    fmt.Println(map_exist(two, "B"))
}

This works, but it probably isn't useful enough for your intended use case.

Another approach is to define a generic map interface and make sure that the functions you intend to use are defined for the types you want to support. Basically, your goal is to build a library that's useful enough that you can reasonably offload the work of implementing your interface to the library's users. It would be nice if you could declare a default function or maybe just a macro to prevent the copy-paste, but I'm not aware of such a mechanism.

Here's an example using an interface:

type GenericMap interface{
    ValueForKey(string) (interface{}, bool)
}

type SliceMap map[string][]string
type StringMap map[string]string
type VoidMap map[string]interface{}

func map_exist(map_val GenericMap, key string) bool {
    _, ok := map_val.ValueForKey(key)
    return ok
}

func (map_val SliceMap) ValueForKey(key string) (interface{}, bool) {
    val, ok := map_val[key]
    return val, ok
}

func (map_val StringMap) ValueForKey(key string) (interface{}, bool) {
    val, ok := map_val[key]
    return val, ok
}

func (map_val VoidMap) ValueForKey(key string) (interface{}, bool) {
    val, ok := map_val[key]
    return val, ok
}

func main() {
    one := SliceMap {
        "A": []string{"a", "b", "c"},
    }
    fmt.Println(map_exist(GenericMap(one), "A"))

    two := StringMap {
        "B": "a",
    }
    fmt.Println(map_exist(GenericMap(two), "B"))
}

In the end, Go programmers tend to prefer a simple, straight-forward solution over all this misdirection, so your best bet is to just use the construct proposed by @Logiraptor:

if _, ok := m[key]; ok {
    // You're ok!
}
Austin Mullins
  • 7,307
  • 2
  • 33
  • 48