I'd like to write a little command-line utility to decode/encode streams of text, like iconv
, but in Go. The user will provide the encoder and decoder names and the utility will check them against charmap.All
to make the user args are valid before trying to decode/encode the stream.
I can iterate charmap.All
and print the names like:
for _, cmap := range charmap.All {
fmt.Println(cmap)
}
I can compare my cmap
var to a known Charmap:
if cmap == charmap.ISO8859_1 {
fmt.Println(charmap.ISO8859_1.String())
}
But I don't know how to do the next step, which seems so tantalizingly close (and easy):
var encoder string
flag.StringVar(&encoder, "encoder", "ISO 8859-1", "name of encoder")
flag.Parse()
for _, cmap := range charmap.All {
if cmap.String() == encoder {
// encode based on user's input
}
}
Is that possible, given the encoding/charmap API?
Also, how is it that my cmap
var and charmap.ISO8859_1
are equivalent (in the cmap == charmap.ISO8859_1
example), but cmap
is really an Encoding interface, and I cannot convert:
charmap.Charmap(cmap).String()
→ cannot convert cmap (type encoding.Encoding) to type charmap.Charmap
I'm still pretty new to Go, and don't fully understand these differences and equivalencies in types and interfaces.
CodePudding user response:
You can break it down as follows, charmap.All is a slice of Encoding interfaces, which can be iterated using a range
loop.
The equality works because the type Charmap, implements the interface, i.e. each charmap type will have a NewDecoder()
and a NewEncoder()
method implementation defined. By the language specification, if a struct implements an interface, they can be compared (See Comparison operators)
A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x
With the above inference, we can understand that the func (*Charmap) String is a method on the Charmap
struct type and not on the interface. So the right way to do this, would be to Type assert your interface value and then call the string function on the same.
for _, enc := range charmap.All {
cmap, ok := enc.(*charmap.Charmap)
if ok && cmap.String() == encoder {
// encode based on user's input
}
}