How to use parse many times in golang's template - go

i need help. Now to output pages I use multiple templates(1 example) and i want to use parse many times in one template(2 example)
Example 1:
...
t, err := template.ParseFiles("header.html")
t.Execute(wr, data)
d, err := template.ParseFiles("content.html")
d.Execute(wr, datatwo)
...
Example 2:
...
t := template.New("blabla")
t.ParseFiles("header.html")
t.ParseFiles("content.html")
t.Execute("wr", data)
P.S. I'm sorry, my english is very bad

template.ParseFiles can take multiple filenames as an argument, as per http://golang.org/pkg/html/template/#ParseFiles
func ParseFiles(filenames ...string) (*Template, error)
e.g.
t := template.New("base")
t, err := t.ParseFiles("header.html", "footer.html", "content.html")
if err != nil {
// handle the error
}
There's a solid example on how to use html/template in the Go docs as well: http://golang.org/doc/articles/wiki/#tmp_6

Related

Passing []net.Conn to io.MultiWriter

I have many of net.Conn and i want to implement multi writer. so i can send data to every available net.Conn.
My current approach is using io.MultiWriter.
func route(conn, dst []net.Conn) {
targets := io.MultiWriter(dst[0], dst[1])
_, err := io.Copy(targets, conn)
if err != nil {
log.Println(err)
}
}
but the problem is, i must specify every net.Conn index in io.MultiWriter and it will be a problem, because the slice size is dynamic.
when i try another approach by pass the []net.Conn to io.MultiWriter, like code below
func route(conn, dst []net.Conn) {
targets := io.MultiWriter(dst...)
_, err := io.Copy(targets, conn)
if err != nil {
log.Println(err)
}
}
there is an error "cannot use mirrors (variable of type []net.Conn) as []io.Writer value in argument to io.MultiWriter"
Is there proper way to handle this case? so i can pass the net.Conn slice to io.MultiWriter.
Thank you.
io.MultiWriter() has a param of type ...io.Writer, so you may only pass a slice of type []io.Writer.
So first create a slice of the proper type, copy the net.Conn values to it, then pass it like this:
ws := make([]io.Writer, len(dst))
for i, c := range dst {
ws[i] = c
}
targets := io.MultiWriter(ws...)

Merge two Text files in Golang

I'm attempting to merge two text files by merging fileACopy.txt to tmp1.txt. The error I get when trying to do this is:
Cannot use 'fileACopy' (type *File) as type []byte"
Both text files have multiple lines of strings and I want to maintain the line breaks. I have imported io, log and os.
How does my code need to be modified or what code should I use?
// Append fileACopy.txt to tmp1.txt
fileACopy, err := os.Open("./fileACopy.txt")
if err != nil {
log.Fatal(err)
}
defer fileACopy.Close()
append, err := os.OpenFile("tmp1.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer append.Close()
if _, err := append.Write(fileACopy); err != nil {
log.Fatal(err)
}
err := os.Remove("fileACopy.txt")
if err != nil {
log.Fatal(err)
}
Consider the definitions of Open and Write:
func Open(name string) (*File, error)
func (f *File) Write(b []byte) (n int, err error)
So the line:
fileACopy, err := os.Open("./fileACopy.txt")
Gives you fileACopy (a *File) and you then pass this as an argument to append.Write(fileACopy). As per the above definitions append.Write takes a []byte and you are trying to pass it something different (fileACopy, a *File) hence the error "Cannot use 'fileACopy' (type *File) as type []byte".
The simplest way to achieve what you want is probably to use io.Copy:
Copy(dst Writer, src Reader) (written int64, err error)
In your case io.Copy(append, fileACopy) should do the trick. A, less efficient, alternative would be to read the file contents using ioutil.ReadAll (amoungst other options) which will give you a []byte which you can then pass to append.Write (this may not work as well because the entire file is read into memory and then written).

error: template: "..." is an incomplete or empty template

I'm trying to add a FuncMap to my templates, but I'm receiving the following error:
template: "foo" is an incomplete or empty
template
The parsing of templates worked just fine before I used the FuncMap, so I'm not sure why it's throwing an error now.
Here is my code:
funcMap := template.FuncMap{
"IntToUSD": func(num int) string {
return decimal.New(int64(num), 2).String()
},
}
// ...
tmpl, err := template.New(t.file).Funcs(funcMap).ParseFiles(t.files()...)
if err != nil {
// ...
}
t.files() just returns a slice of strings that are file paths.
Anyone know what's up?
Make sure the argument you pass to template.New is the base name of one of the files in the list you pass to ParseFiles.
One option is
files := t.files()
if len(files) > 0 {
name := path.Base(files[0])
tmpl, err := template.New(name).Funcs(funcMap).ParseFiles(files...)
ParseFiles documentation:
Since the templates created by ParseFiles are named by the base names of the argument files, t should usually have the name of one of the (base) names of the files.
I was having the same problem. I realized that
tmpl, err := template.New("").Funcs(funcMap).ParseFiles("fileName")
also works if you use it with
err := tpl.ExecuteTemplate(wr, "fileName", data)
If I use
err := tpl.Execute(wr, data)
then I should specify the template name in New():
tmpl, err := template.New("fileName").Funcs(funcMap).ParseFiles("fileName")
You can also use Template.Must method,
templ = template.Must(template.New("fileName").Funcs(fm).ParseFiles("fileName"))

Passing []*io.PipeWriter to io.MultiWriter

I have a bunch of *io.PipeWriter created and would like to make a multiwriter based on all those pipewriters in a function. So I call a function something like
func copyToWriters(reader *bufio.Reader, errs chan error, writers []*io.PipeWriter) {
for _, writer := range writers {
defer writer.Close()
}
mw := io.MultiWriter(writers)
_, err := io.Copy(mw, reader)
if err != nil {
errs <- err
}
}
I call the method with arguments copyToWriters(reader, errs, []*io.PipeWriter{w1, w2})
But it says
cannot use writers (type []*io.PipeWriter) as type []io.Writer in argument to io.MultiWriter. But
if I change io.MultiWriter(writers) to io.MultiWriter(writers[0],writers[1]) it works. How can I make the existing function work by not having to pass writers separately.
Unfortunately, Golang's type system does not allow casting []*io.PipeWriter to []io.Writer even when *io.PipeWriter implements io.Writer since it requires O(n) operation (reference).
The best you can do is create another []io.Writer and copy the pipe writers into it
ws := make([]io.Writer, len(writers))
for i, w := range writers {
ws[i] = w
}
mw := io.MultiWriter(ws...)
And reason why you nead ..., read the document

Go — handling multiple errors elegantly?

Is there a way to clean up this (IMO) horrific-looking code?
aJson, err1 := json.Marshal(a)
bJson, err2 := json.Marshal(b)
cJson, err3 := json.Marshal(c)
dJson, err4 := json.Marshal(d)
eJson, err5 := json.Marshal(e)
fJson, err6 := json.Marshal(f)
gJson, err4 := json.Marshal(g)
if err1 != nil {
return err1
} else if err2 != nil {
return err2
} else if err3 != nil {
return err3
} else if err4 != nil {
return err4
} else if err5 != nil {
return err5
} else if err5 != nil {
return err5
} else if err6 != nil {
return err6
}
Specifically, I'm talking about the error handling. It would be nice to be able to handle all the errors in one go.
var err error
f := func(dest *D, src S) bool {
*dest, err = json.Marshal(src)
return err == nil
} // EDIT: removed ()
f(&aJson, a) &&
f(&bJson, b) &&
f(&cJson, c) &&
f(&dJson, d) &&
f(&eJson, e) &&
f(&fJson, f) &&
f(&gJson, g)
return err
Put the result in a slice instead of variables, put the intial values in another slice to iterate and return during the iteration if there's an error.
var result [][]byte
for _, item := range []interface{}{a, b, c, d, e, f, g} {
res, err := json.Marshal(item)
if err != nil {
return err
}
result = append(result, res)
}
You could even reuse an array instead of having two slices.
var values, err = [...]interface{}{a, b, c, d, e, f, g}, error(nil)
for i, item := range values {
if values[i], err = json.Marshal(item); err != nil {
return err
}
}
Of course, this'll require a type assertion to use the results.
define a function.
func marshalMany(vals ...interface{}) ([][]byte, error) {
out := make([][]byte, 0, len(vals))
for i := range vals {
b, err := json.Marshal(vals[i])
if err != nil {
return nil, err
}
out = append(out, b)
}
return out, nil
}
you didn't say anything about how you'd like your error handling to work. Fail one, fail all? First to fail? Collect successes or toss them?
I believe the other answers here are correct for your specific problem, but more generally, panic can be used to shorten error handling while still being a well-behaving library. (i.e., not panicing across package boundaries.)
Consider:
func mustMarshal(v interface{}) []byte {
bs, err := json.Marshal(v)
if err != nil {
panic(err)
}
return bs
}
func encodeAll() (err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
if err, ok = r.(error); ok {
return
}
panic(r)
}
}()
ea := mustMarshal(a)
eb := mustMarshal(b)
ec := mustMarshal(c)
return nil
}
This code uses mustMarshal to panic whenever there is a problem marshaling a value. But the encodeAll function will recover from the panic and return it as a normal error value. The client in this case is never exposed to the panic.
But this comes with a warning: using this approach everywhere is not idiomatic. It can also be worse since it doesn't lend itself well to handling each individual error specially, but more or less treating each error the same. But it has its uses when there are tons of errors to handle. As an example, I use this kind of approach in a web application, where a top-level handler can catch different kinds of errors and display them appropriately to the user (or a log file) depending on the kind of error.
It makes for terser code when there is a lot of error handling, but at the loss of idiomatic Go and handling each error specially. Another down-side is that it could prevent something that should panic from actually panicing. (But this can be trivially solved by using your own error type.)
You can use go-multierror by Hashicorp.
var merr error
if err := step1(); err != nil {
merr = multierror.Append(merr, err)
}
if err := step2(); err != nil {
merr = multierror.Append(merr, err)
}
return merr
You can create a reusable method to handle multiple errors, this implementation will only show the last error but you could return every error msg combined by modifying the following code:
func hasError(errs ...error) error {
for i, _ := range errs {
if errs[i] != nil {
return errs[i]
}
}
return nil
}
aJson, err := json.Marshal(a)
bJson, err1 := json.Marshal(b)
cJson, err2 := json.Marshal(c)
if error := hasError(err, err1, err2); error != nil {
return error
}
Another perspective on this is, instead of asking "how" to handle the abhorrent verbosity, whether we actually "should". This advice is heavily dependent on context, so be careful.
In order to decide whether handling the json.Marshal error is worth it, we can inspect its implementation to see when errors are returned. In order to return errors to the caller and preserve code terseness, json.Marshal uses panic and recover internally in a manner akin to exceptions. It defines an internal helper method which, when called, panics with the given error value. By looking at each call of this function, we learn that json.Marshal errors in the given scenarios:
calling MarshalJSON or MarshalText on a value/field of a type which implements json.Marshaler or encoding.TextMarshaler returns an error—in other words, a custom marshaling method fails;
the input is/contains a cyclic (self-referencing) structure;
the input is/contains a value of an unsupported type (complex, chan, func);
the input is/contains a floating-point number which is NaN or Infinity (these are not allowed by the spec, see section 2.4);
the input is/contains a json.Number string that is an incorrect number representation (for example, "foo" instead of "123").
Now, a usual scenario for marshaling data is creating an API response, for example. In that case, you will 100% have data types that satisfy all of the marshaler's constraints and valid values, given that the server itself generates them. In the situation user-provided input is used, the data should be validated anyway beforehand, so it should still not cause issues with the marshaler. Furthermore, we can see that, apart from the custom marshaler errors, all the other errors occur at runtime because Go's type system cannot enforce the required conditions by itself. With all these points given, here comes the question: given our control over the data types and values, do we need to handle json.Marshal's error at all?
Probably no. For a type like
type Person struct {
Name string
Age int
}
it is now obvious that json.Marshal cannot fail. It is trickier when the type looks like
type Foo struct {
Data any
}
(any is a new Go 1.18 alias for interface{}) because there is no compile-time guarantee that Foo.Data will hold a value of a valid type—but I'd still argue that if Foo is meant to be serialized as a response, Foo.Data will also be serializable. Infinity or NaN floats remain an issue, but, given the JSON standard limitation, if you want to serialize these two special values you cannot use JSON numbers anyway, so you'll have to look for another solution, which means that you'll end up avoiding the error anyway.
To conclude, my point is that you can probably do:
aJson, _ := json.Marshal(a)
bJson, _ := json.Marshal(b)
cJson, _ := json.Marshal(c)
dJson, _ := json.Marshal(d)
eJson, _ := json.Marshal(e)
fJson, _ := json.Marshal(f)
gJson, _ := json.Marshal(g)
and live fine with it. If you want to be pedantic, you can use a helper such as:
func must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
(note the Go 1.18 generics usage) and do
aJson := must(json.Marshal(a))
bJson := must(json.Marshal(b))
cJson := must(json.Marshal(c))
dJson := must(json.Marshal(d))
eJson := must(json.Marshal(e))
fJson := must(json.Marshal(f))
gJson := must(json.Marshal(g))
This will work nice when you have something like an HTTP server, where each request is wrapped in a middleware that recovers from panics and responds to the client with status 500. It's also where you would care about these unexpected errors—when you don't want the program/service to crash at all. For one-time scripts you'll probably want to have the operation halted and a stack trace dumped.
If you're unsure of how your types will be changed in the future, you don't trust your tests, data may not be in your full control, the codebase is too big to trace the data or whatever other reason which causes uncertainty over the correctness of your data, it is better to handle the error. Pay attention to the context you're in!
P.S.: Pragmatically ignoring errors should be generally sought after. For example, the Write* methods on bytes.Buffer, strings.Builder never return errors; fmt.Fprintf, with a valid format string and a writer that doesn't return errors, also returns no errors; bufio.Writer aswell doesn't, if the underlying writer doesn't return. You will find some types implement interfaces with methods that return errors but don't actually return any. In these cases, if you know the concrete type, handling errors is unnecessarily verbose and redundant. What do you prefer,
var sb strings.Builder
if _, err := sb.WriteString("hello "); err != nil {
return err
}
if _, err := sb.WriteString("world!"); err != nil {
return err
}
or
var sb strings.Builder
sb.WriteString("hello ")
sb.WriteString("world!")
(of course, ignoring that it could be a single WriteString call)?
The given examples write to an in-memory buffer, which unless the machine is out of memory, an error which you cannot handle in Go, cannot ever fail. Other such situations will surface in your code—blindly handling errors adds little to no value! Caution is key—if an implementation changes and does return errors, you may be in trouble. Standard library or well-established packages are good candidates for eliding error checking, if possible.

Resources