Note: I'm editing this question to a concrete example of why I want to do this, which is why some of the answers might no longer make sense in context.
I am writing a bit of code that passes data from an input. The data is in the form of tags that have an identifier of what kind of data they contain and then the data.
Unfortunately I have no control over the input and don't know in advance what tags will be in it, one might be an int another might be a string, yet another might be an array of ints.
The problem arises when I need to handle all tags like the same type, for instance if I have a slice of tags, of a function that either accepts or returns a tag.
The solutions I have so far seen to this is to define the slices/functions with an empty interface which would allow me to do so, however that is kinda undesirable as it would not tell anything to other people using the package about what types are expected and also kinda defies the point of having a typed language in the first place.
Interfaces does however seem to be the solution here, and i would love to have a Tag
interface to pass around, that does require though that I define methods on them, and there are really no methods they need.
My current solution looks like this
type Tag interface{
implementTag()
}
type TagInt int
func (tag TagInt) implementTag() {}
type TagString string
func (tag TagInt) implementTag() {}
While this does indeed work and solves my problem, having to define dummy methods just for that feels very wrong.
So my question sums up in this: Are there any way that I can define that something is a Tag
without having to define dummy methods?
You can use []interface{}
for a "slice of any type" but then it's up to you to use type assertions and/or type switches to discover the actual runtime types of that slice's members.
Learn more about empty interfaces in the Tour of Go
And now want to make a slice that can hold both t1 and t2 but nothing else.
This is quite an unusual requirement and you're unlikely to need this in Go. But you could also do your own discriminated union with:
type item struct {
typeSelector int
t1Value t1
t2Value t2
}
And then use []item
, checking typeSelector
at runtime to see which value is populated.
Alternatively you could even use *t1
and *t2
and have nil
signify "no value in this field".
And now want to make a slice that can hold both t1 and t2 but nothing else.
You cannot do that. Sorry.
What I would do in your scenario is accept any type in the parameters with an empty interface then use a type assertion inside to confirm that it's the type that you want.
if t1, ok := interfaceInput.(t1); !ok{
// handle it being the wrong type here
return
}
Also if you want the tight coupling between a data type and it's method, namely an object, what's so wrong with having it be a method of the object?