I need to use the *template.Execute method but I want the result as a string or byte[] so that I can pass it to another *template.Execute but the method writes its results to a writer. Is there a way to create a writer that will write to a variable I define?
Use an instance of bytes.Buffer, which implements io.Writer:
var buff bytes.Buffer
if err := tpl.Execute(&buff, data); err != nil {
panic(err)
}
You can then get a string result using buff.String(), or a []byte result using buff.Bytes().
You can also use strings.Builder for this purpose:
package main
import (
"html/template"
"strings"
)
func main() {
t, e := template.New("date").Parse("<p>{{ .month }} - {{ .day }}</p>")
if e != nil {
panic(e)
}
b := new(strings.Builder)
t.Execute(b, map[string]int{"month": 12, "day": 31})
println(b.String())
}
https://golang.org/pkg/strings#Builder
Related
I try to understand why both functions return the same output.
As far as I understood, the point of omit empty is to not add that key to the result struct.
I wrote this example, I was expecting the first output not to have the "Empty" key, but for some reason its value still shows as 0.
package main
import (
"encoding/json"
"fmt"
"strings"
)
type agentOmitEmpty struct {
Alias string `json:"Alias,omitempty"`
Skilled bool `json:"Skilled,omitempty"`
FinID int32 `json:"FinId,omitempty"`
Empty int `json:"Empty,omitempty"`
}
type agent struct {
Alias string `json:"Alias"`
Skilled bool `json:"Skilled"`
FinID int32 `json:"FinId"`
Empty int `json:"Empty"`
}
func main() {
jsonString := `{
"Alias":"Robert",
"Skilled":true,
"FinId":12345
}`
fmt.Printf("output with omit emtpy: %v\n", withEmpty(strings.NewReader(jsonString)))
// output with omit emtpy: {Robert true 12345 0}
fmt.Printf("output regular: %v\n", withoutEmpty(strings.NewReader(jsonString)))
// output without omit: {Robert true 12345 0}
}
func withEmpty(r *strings.Reader) agentOmitEmpty {
dec := json.NewDecoder(r)
body := agentOmitEmpty{}
err := dec.Decode(&body)
if err != nil {
panic(err)
}
return body
}
func withoutEmpty(r *strings.Reader) agent {
dec := json.NewDecoder(r)
body := agent{}
err := dec.Decode(&body)
if err != nil {
panic(err)
}
return body
}
You need to define Empty as *int so it will be replaced with nil when there is no value. Then it will not be saved in the database.
Query Api and response a custom JSON, how to Unmarshal it. the sample JSON:
{"14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu": {
"final_balance": 61914248289,
"n_tx": 3472,
"total_received": 3479994002972
}}
The key is a hex string. So how to handle it with golang convention, anyone can help me?
Below is my try test code:
c.OnResponse(func(r *colly.Response) {
jsonData := r.Body
fmt.Println(string(jsonData))
fmt.Println("==================")
//parse bitcoin json
jsonMap := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonData), &jsonMap)
if err != nil {
panic(err)
}
fmt.Println(jsonMap)
dumpMap("", jsonMap)
})
func dumpMap(space string, m map[string]interface{}) {
for k, v := range m {
if mv, ok := v.(map[string]interface{}); ok {
fmt.Printf("{ \"%v\": \n", k)
dumpMap(space+"\t", mv)
fmt.Printf("}\n")
} else {
fmt.Printf("%v %v : %v\n", space, k, v)
}
}
}
and go run cmd/main.go, the console is print here:
{"14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu": {
"final_balance": 75494521080,
"n_tx": 3493,
"total_received": 3493574275763
}}
==================
map[14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu:map[n_tx:3493 total_received:3.493574275763e+12 final_balance:7.549452108e+10]]
{ "14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu":
final_balance : 7.549452108e+10
n_tx : 3493
total_received : 3.493574275763e+12
}
Do I need customised unmarshal func to get string key? If I use 14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu as key I can't easily to access. I just want to know how handle it.
you can unmarshal it into map, so you can get generated key as a key of map
https://play.golang.org/p/IfEjjvKakpu
package main
import (
"encoding/json"
"fmt"
"log"
)
var input = `{"14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu": {
"final_balance": 61914248289,
"n_tx": 3472,
"total_received": 3479994002972
}}`
type object struct {
FinalBalance uint64 `json:"final_balance"`
NTX uint64 `json:"n_tx"`
TotalReceived uint64 `json:"total_received"`
}
func main() {
var result map[string]object;
err := json.Unmarshal([]byte(input), &result);
if err != nil {
log.Fatal(err)
}
fmt.Printf("result: %+v", result)
// result: map[14AcKEr19gHJvgwQhK7sfFm6YJGmoZZoqu:{FinalBalance:61914248289 NTX:3472 TotalReceived:3479994002972}]
}
How can I use division in a golang template. I need to divide Id by 2.
For example
{{if .Id/2}}
HEY, I CAN DO IT!
{{else}}
WHY???
{{end}}
The package text/template (and subsequently html/template) can provide the functionality by defining division as a function using Template.Funcs:
func (t *Template) Funcs(funcMap FuncMap) *Template
In your case, a FuncMap with a divide function could look something like this:
fm := template.FuncMap{"divide": func(a, b int) int {
return a / b
}}
Full example (but without me trying to understand what you mean with if a/2):
package main
import (
"os"
"text/template"
)
func main() {
fm := template.FuncMap{"divide": func(a, b int) int {
return a / b
}}
tmplTxt := `{{divide . 2}}`
// Create a template, add the function map, and parse the text.
tmpl, err := template.New("foo").Funcs(fm).Parse(tmplTxt)
if err != nil {
panic(err)
}
// Run the template to verify the output.
err = tmpl.Execute(os.Stdout, 10)
if err != nil {
panic(err)
}
}
Output:
5
Playground: http://play.golang.org/p/VOhTYbdj6P
Could someone help me please what's going wrong here? For some reason the output are not the same and I don't get why.
type rTime time.Time
func (rt *rTime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
log.Println(t)
*rt = rTime(t)
log.Println(*rt)
return nil
}
Log looks like this:
2014/09/18 04:31:35 1999-10-15 00:00:00 +0000 UTC
2014/09/18 04:31:35 {63075542400 0 0x933ea0}
Why's the conversion not working? The input string is 1995-10-15 btw.
The conversion is working, but fmt.Println() looks for a String() method, and that exists on time.Time but not on your type. You should need nothing more than func (rt rTime) String() string { return time.Time(rt).String() } to direct String() calls back to time.Time's implementation.
Here's an example:
package main
import (
"log"
"time"
)
type rTime time.Time
func (rt rTime) String() string { return time.Time(rt).String() }
func main() {
s := "1999-10-15"
t, err := time.Parse("2006-01-02", s)
if err != nil {
panic(err)
}
log.Println(t)
rt := rTime(t)
log.Println(rt)
}
Note that I treated both time types as values because the standard library does, per the canonical advice to avoid pointers for tiny structs with value semantics.
Maybe more interesting, you can use type embedding to automagically pick up all of the methods of time.Time except any you override. The syntax changes slightly (see on Playground):
package main
import (
"log"
"time"
)
type rTime struct { time.Time }
func main() {
s := "1999-10-15"
t, err := time.Parse("2006-01-02", s)
if err != nil {
panic(err)
}
log.Println(t)
rt := rTime{t}
log.Println(rt)
}
If you've used embedding and want to write your own custom methods that "proxy through" to the embedded type's, you use a syntax like obj.EmbeddedTypeName.Method, which could be like, for instance, rt.Time.String():
// a custom String method that adds smiley faces
func (rt rTime) String() string { return "😁 " + rt.Time.String() + " 😁" }
obj.EmbeddedTypeName is also how you (for example) access operators on non-struct types that you've embedded.
I'm still quite new to Go and I was surprised to not be able to use the subtype of an embedded interface.
Here is a small example to explain what I mean:
func test(sl bufio.ReadWriter){
// cannot use sl(type bufio.ReadWriter) as type bufio.Reader in function argument
readStuff(sl)
[...]
writeStuff(sl) // same kind of error
}
func readStuff(sl bufio.Reader){
[...]
}
As every interface have the same memory layout and ReadWriter is a Reader and a Writer, I was expecting this code to work.
I did try to convert the interface type with:
readStuff(sl.(buffio.Reader))
But it doesn't work either. So I've got two questions:
Why doesn't it work?
What's the go philosophy about that problem?
They're different types. However, a bufio.ReadWriter contains a pointer to both a bufio.Reader type and a bufio.Writer type as elements of its struct. So passing the correct one should be easy enough. Try this:
func test(sl bufio.ReadWriter){
readStuff(sl.Reader)
[...]
writeStuff(sl.Writer)
}
// Changed this bufio.Reader to a pointer receiver
func readStuff(sl *bufio.Reader) {
[...]
}
bufio.ReadWriter is a concrete type, not an interface. However, it does satisfy an interface (io.ReadWriter) so it can be assigned to a variable/function argument of an appropriate interface type. Then it works the way you may have anticipated (your code actually doesn't use any interfaces):
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
)
func readStuff(r io.Reader) {
b := make([]byte, 10)
n, err := r.Read(b)
if err != nil && err != io.EOF {
log.Fatal(err)
}
fmt.Printf("readStuff: %q\n", b[:n])
}
func writeStuff(w io.Writer) {
b := []byte("written")
n, err := w.Write(b)
if n != len(b) {
log.Fatal("Short write")
}
if err != nil {
log.Fatal(err)
}
}
func test(rw io.ReadWriter) {
readStuff(rw)
writeStuff(rw)
}
func main() {
r := io.Reader(bytes.NewBufferString("source"))
var uw bytes.Buffer
w := io.Writer(&uw)
rw := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w))
test(rw)
rw.Flush()
fmt.Printf("The underlying bytes.Buffer writer contains %q\n", uw.Bytes())
}
(Also here)
Output:
readStuff: "source"
The underlying bytes.Buffer writer contains "written"
This way test can consume any io.ReadWriter, not only a specific one. Which is a hint towards your question about go "philosophy".