The code is given below
fmt.Printf("%7s: %-48s
", "IQN", annotations.Iqn)
fmt.Printf("%7s: %-16s
", "Volume", args[0])
fmt.Printf("%7s: %-15s
", "Portal", annotations.TargetPortal)
fmt.Printf("%7s: %-6s
", "Size", annotations.VolSize)
No, there is not.
But you can write a utility function which automates all these, and all you need to do is pass the key-value pairs you want to pretty-print.
Let's model the key-values with this type:
type KeyValue struct {
Key string
Value interface{}
}
Note the value may be of any type, not just a string
value. We'll use the default formatting when printing it. If you want a format other than the default, you can always convert it to string
to your liking, and set that as the value.
The pretty-print utility function (explanation follows below):
var aligns = map[bool]string{true: "-"}
func printKeyValues(keyRight, valueRight bool, kvs ...KeyValue) {
// First convert values to string and find max key and max value lengths:
values := make([]string, len(kvs))
maxKey, maxValue := 0, 0
for i, kv := range kvs {
if length := utf8.RuneCountInString(kv.Key); length > maxKey {
maxKey = length
}
values[i] = fmt.Sprint(kv.Value)
if length := utf8.RuneCountInString(values[i]); length > maxValue {
maxValue = length
}
}
// Generate format string:
fs := fmt.Sprintf("%%%s%ds: %%%s%ds|
",
aligns[keyRight], maxKey+1, aligns[valueRight], maxValue+1)
// And now print the key-values:
for i, kv := range kvs {
fmt.Printf(fs, kv.Key, values[i])
}
}
Testing it:
printKeyValues(false, true, []KeyValue{
{"IQN", "asdfl;kj"},
{"Volume", "asdf;lkjasdf"},
{"Portal", "asdf"},
{"Size", 12345678},
}...)
Output:
IQN: asdfl;kj |
Volume: asdf;lkjasdf |
Portal: asdf |
Size: 12345678 |
Another test:
printKeyValues(true, false, []KeyValue{
{"IQN", "asdfl;kj"},
{"Volume", "asdf;lkjasdf"},
{"Portal", "asdf"},
{"Size", 12345678},
}...)
Output:
IQN : asdfl;kj|
Volume : asdf;lkjasdf|
Portal : asdf|
Size : 12345678|
Try the examples on the Go Playground.
The printKeyValues()
first ranges over the key-value pairs, and converts values to string
values, using the default formatting by calling fmt.Sprint()
. Now we can find the max key length and the max value length. Note that length of a string
is not len(s)
, as that returns the byte-length in UTF-8 encoding (which is how Go stores strings in memory). Instead to get the number of characters (or more precisely the number of rune
s), we used utf8.RuneCountInString()
.
Once we have this, we can generate the format string where the max key length and max value length is used. We will also give the possibility to control whether we want to align keys and values to the left or right, in the format string this means a -
sign in case of right alignment. To get an empty string ""
in case of left and a "-"
in case of right, for compact code I used a simple map:
var aligns = map[bool]string{true: "-"}
Indexing this map with false
gives the zero value of the value type of the map which is ""
, and indexing it with true
will give the associated value which is "-"
. And since this map is always the same, I moved it outside of the function (small optimization).
To generate the format string we used fmt.Sprintf()
:
fs := fmt.Sprintf("%%%s%ds: %%%s%ds|
",
aligns[keyRight], maxKey+1, aligns[valueRight], maxValue+1)
Note that %
signs need to be doubled as that is special in format strings.
One final task remained: to use the generated format string to print all key-value pairs.
Thanks @icza, i found one more way, have a look on this :-)
package main
import (
"text/template"
"os"
)
func main() {
type Annotations struct {
IQN string
Volume string
Portal string
Size string
}
annotation := Annotations{
IQN: "openebs.io",
Volume: "vol",
Portal: "10.29.1.1:3260",
Size: "1G",
}
tmpl, err := template.New("test").Parse("IQN :
{{.IQN}}
Volume : {{.Volume}}
Portal : {{.Portal}}
Size :
{{.Size}}")
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, annotation)
if err != nil {
panic(err)
}
}
Output :
IQN : openebs.io
Volume : vol
Portal : 10.29.1.1:3260
Size : 1G
Here is the link The Go Playground