Add en/0.7.x.md syntax highlighting
This commit is contained in:
32
en/07.1.md
32
en/07.1.md
@@ -5,7 +5,7 @@ XML is a commonly used data communication format in web services. Today, it's as
|
||||
I will not make any attempts to teach XML's syntax or conventions. For that, please read more documentation about XML itself. We will only focus on how to encode and decode XML files in Go.
|
||||
|
||||
Suppose you work in IT, and you have to deal with the following XML configuration file:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<servers version="1">
|
||||
<server>
|
||||
@@ -17,7 +17,7 @@ Suppose you work in IT, and you have to deal with the following XML configuratio
|
||||
<serverIP>127.0.0.2</serverIP>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
```
|
||||
The above XML document contains two kinds of information about your server: the server name and IP. We will use this document in our following examples.
|
||||
|
||||
## Parse XML
|
||||
@@ -29,7 +29,7 @@ How do we parse this XML document? We can use the `Unmarshal` function in Go's `
|
||||
the `data` parameter receives a data stream from an XML source, and `v` is the structure you want to output the parsed XML to. It is an interface, which means you can convert XML to any structure you desire. Here, we'll only talk about how to convert from XML to the `struct` type since they share similar tree structures.
|
||||
|
||||
Sample code:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -73,9 +73,9 @@ Sample code:
|
||||
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
```
|
||||
XML is actually a tree data structure, and we can define a very similar structure using structs in Go, then use `xml.Unmarshal` to convert from XML to our struct object. The sample code will print the following content:
|
||||
|
||||
```xml
|
||||
{{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}]
|
||||
<server>
|
||||
<serverName>Shanghai_VPN</serverName>
|
||||
@@ -86,11 +86,11 @@ XML is actually a tree data structure, and we can define a very similar structur
|
||||
<serverIP>127.0.0.2</serverIP>
|
||||
</server>
|
||||
}
|
||||
|
||||
```
|
||||
We use `xml.Unmarshal` to parse the XML document to the corresponding struct object. You should see that we have something like `xml:"serverName"` in our struct. This is a feature of structs called `struct tags` for helping with reflection. Let's see the definition of `Unmarshal` again:
|
||||
|
||||
```Go
|
||||
func Unmarshal(data []byte, v interface{}) error
|
||||
|
||||
```
|
||||
The first argument is an XML data stream. The second argument is storage type and supports the struct, slice and string types. Go's XML package uses reflection for data mapping, so all fields in v should be exported. However, this causes a problem: how does it know which XML field corresponds to the mapped struct field? The answer is that the XML parser parses data in a certain order. The library will try to find the matching struct tag first. If a match cannot be found then it searches through the struct field names. Be aware that all tags, field names and XML elements are case sensitive, so you have to make sure that there is a one-to-one correspondence for the mapping to succeed.
|
||||
|
||||
Go's reflection mechanism allows you to use this tag information to reflect XML data to a struct object. If you want to know more about reflection in Go, please read the package documentation on struct tags and reflection.
|
||||
@@ -116,14 +116,14 @@ Note that all fields in structs should be exported (capitalized) in order to par
|
||||
## Produce XML
|
||||
|
||||
What if we want to produce an XML document instead of parsing one. How do we do this in Go? Unsurprisingly, the `xml` package provides two functions which are `Marshal` and `MarshalIndent`, where the second function automatically indents the marshalled XML document. Their definition as follows:
|
||||
|
||||
```Go
|
||||
func Marshal(v interface{}) ([]byte, error)
|
||||
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
|
||||
|
||||
```
|
||||
The first argument in both of these functions is for storing a marshalled XML data stream.
|
||||
|
||||
Let's look at an example to see how this works:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -155,9 +155,9 @@ Let's look at an example to see how this works:
|
||||
|
||||
os.Stdout.Write(output)
|
||||
}
|
||||
|
||||
```
|
||||
The above example prints the following information:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<servers version="1">
|
||||
<server>
|
||||
@@ -169,7 +169,7 @@ The above example prints the following information:
|
||||
<serverIP>127.0.0.2</serverIP>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
```
|
||||
As we've previously defined, the reason we have `os.Stdout.Write([]byte(xml.Header))` is because both `xml.MarshalIndent` and `xml.Marshal` do not output XML headers on their own, so we have to explicitly print them in order to produce XML documents correctly.
|
||||
|
||||
Here we can see that `Marshal` also receives a v parameter of type `interface{}`. So what are the rules when marshalling to an XML document?
|
||||
@@ -198,7 +198,7 @@ Then we need to figure out how to set tags in order to produce the final XML doc
|
||||
- If a tag contains `",comment"`, it prints it as a comment without escaping, so you cannot have "--" in its value.
|
||||
- If a tag contains `"omitempty"`, it omits this field if its value is zero-value, including false, 0, nil pointer or nil interface, zero length of array, slice, map and string.
|
||||
- If a tag contains `"a>b>c"`, it prints three elements where a contains b and b contains c, like in the following code:
|
||||
|
||||
```xml
|
||||
FirstName string `xml:"name>first"`
|
||||
LastName string `xml:"name>last"`
|
||||
|
||||
@@ -206,7 +206,7 @@ Then we need to figure out how to set tags in order to produce the final XML doc
|
||||
<first>Asta</first>
|
||||
<last>Xie</last>
|
||||
</name>
|
||||
|
||||
```
|
||||
You may have noticed that struct tags are very useful for dealing with XML, and the same goes for the other data formats we'll be discussing in the following sections. If you still find that you have problems with working with struct tags, you should probably read more documentation about them before diving into the next section.
|
||||
|
||||
## Links
|
||||
|
||||
60
en/07.2.md
60
en/07.2.md
@@ -7,9 +7,9 @@ The biggest difference between JSON and XML is that XML is a complete markup lan
|
||||
Since JSON is becoming more and more important in web development, let's take a look at the level of support Go has for JSON. You'll find that Go's standard library has very good support for encoding and decoding JSON.
|
||||
|
||||
Here we use JSON to represent the example in the previous section:
|
||||
|
||||
```json
|
||||
{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}
|
||||
|
||||
```
|
||||
The rest of this section will use this JSON data to introduce JSON concepts in Go.
|
||||
|
||||
## Parse JSON
|
||||
@@ -17,11 +17,11 @@ The rest of this section will use this JSON data to introduce JSON concepts in G
|
||||
### Parse to struct
|
||||
|
||||
Suppose we have the JSON in the above example. How can we parse this data and map it to a struct in Go? Go provides the following function for just this purpose:
|
||||
|
||||
```Go
|
||||
func Unmarshal(data []byte, v interface{}) error
|
||||
|
||||
```
|
||||
We can use this function like so:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -44,7 +44,7 @@ We can use this function like so:
|
||||
json.Unmarshal([]byte(str), &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
```
|
||||
In the above example, we defined a corresponding structs in Go for our JSON, using slice for an array of JSON objects and field name as our JSON keys. But how does Go know which JSON object corresponds to which specific struct filed? Suppose we have a key called `Foo` in JSON. How do we find its corresponding field?
|
||||
|
||||
- First, Go tries to find the (capitalised) exported field whose tag contains `Foo`.
|
||||
@@ -65,16 +65,16 @@ We know that an interface{} can be anything in Go, so it is the best container t
|
||||
- `nil` represents `JSON null`.
|
||||
|
||||
Suppose we have the following JSON data:
|
||||
|
||||
```Go
|
||||
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
|
||||
|
||||
```
|
||||
Now we parse this JSON to an interface{}:
|
||||
|
||||
```Go`
|
||||
var f interface{}
|
||||
err := json.Unmarshal(b, &f)
|
||||
|
||||
```
|
||||
The `f` stores a map, where keys are strings and values are interface{}'s'.
|
||||
|
||||
```Go`
|
||||
f = map[string]interface{}{
|
||||
"Name": "Wednesday",
|
||||
"Age": 6,
|
||||
@@ -83,13 +83,13 @@ The `f` stores a map, where keys are strings and values are interface{}'s'.
|
||||
"Morticia",
|
||||
},
|
||||
}
|
||||
|
||||
```
|
||||
So, how do we access this data? Type assertion.
|
||||
|
||||
```Go`
|
||||
m := f.(map[string]interface{})
|
||||
|
||||
```
|
||||
After asserted, you can use the following code to access data:
|
||||
|
||||
```Go
|
||||
for k, v := range m {
|
||||
switch vv := v.(type) {
|
||||
case string:
|
||||
@@ -107,11 +107,11 @@ After asserted, you can use the following code to access data:
|
||||
fmt.Println(k, "is of a type I don't know how to handle")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
As you can see, we can now parse JSON of an unknown format through interface{} and type assertion.
|
||||
|
||||
The above example is the official solution, but type asserting is not always convenient. So, I recommend an open source project called `simplejson`, created and maintained by bitly. Here is an example of how to use this project to deal with JSON of an unknown format:
|
||||
|
||||
```Go
|
||||
js, err := NewJson([]byte(`{
|
||||
"test": {
|
||||
"array": [1, "2", 3],
|
||||
@@ -126,17 +126,17 @@ The above example is the official solution, but type asserting is not always con
|
||||
arr, _ := js.Get("test").Get("array").Array()
|
||||
i, _ := js.Get("test").Get("int").Int()
|
||||
ms := js.Get("test").Get("string").MustString()
|
||||
|
||||
```
|
||||
It's not hard to see how convenient this is. Check out the repository to see more information: [https://github.com/bitly/go-simplejson](https://github.com/bitly/go-simplejson).
|
||||
|
||||
## Producing JSON
|
||||
|
||||
In many situations, we need to produce JSON data and respond to clients. In Go, the JSON package has a function called `Marshal` to do just that:
|
||||
|
||||
```Go
|
||||
func Marshal(v interface{}) ([]byte, error)
|
||||
|
||||
```
|
||||
Suppose we need to produce a server information list. We have following sample:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -163,13 +163,13 @@ Suppose we need to produce a server information list. We have following sample:
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
```json
|
||||
{"Servers":[{"ServerName":"Shanghai_VPN","ServerIP":"127.0.0.1"},{"ServerName":"Beijing_VPN","ServerIP":"127.0.0.2"}]}
|
||||
|
||||
```
|
||||
As you know, all field names are capitalized, but if you want your JSON key names to start with a lower case letter, you should use `struct tag`s. Otherwise, Go will not produce data for internal fields.
|
||||
|
||||
```Go
|
||||
type Server struct {
|
||||
ServerName string `json:"serverName"`
|
||||
ServerIP string `json:"serverIP"`
|
||||
@@ -178,7 +178,7 @@ As you know, all field names are capitalized, but if you want your JSON key name
|
||||
type Serverslice struct {
|
||||
Servers []Server `json:"servers"`
|
||||
}
|
||||
|
||||
```
|
||||
After this modification, we can produce the same JSON data as before.
|
||||
|
||||
Here are some points you need to keep in mind when trying to produce JSON:
|
||||
@@ -189,7 +189,7 @@ Here are some points you need to keep in mind when trying to produce JSON:
|
||||
- If the field type is `bool`, string, int, `int64`, etc, and its tag contains `",string"`, Go converts this field to its corresponding JSON type.
|
||||
|
||||
Example:
|
||||
|
||||
```Go
|
||||
type Server struct {
|
||||
// ID will not be outputed.
|
||||
ID int `json:"-"`
|
||||
@@ -210,11 +210,11 @@ Example:
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
os.Stdout.Write(b)
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
```json
|
||||
{"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""}
|
||||
|
||||
```
|
||||
The `Marshal` function only returns data when it has succeeded, so here are some points we need to keep in mind:
|
||||
|
||||
- JSON only supports strings as keys, so if you want to encode a map, its type has to be `map[string]T`, where `T` is the type in Go.
|
||||
|
||||
48
en/07.3.md
48
en/07.3.md
@@ -10,24 +10,24 @@ If you recall form validation from previous sections, we used Regexp to verify t
|
||||
## Match
|
||||
|
||||
The `regexp` package has 3 functions to match: if it matches a pattern, then it returns true, returning false otherwise.
|
||||
|
||||
```Go
|
||||
func Match(pattern string, b []byte) (matched bool, error error)
|
||||
func MatchReader(pattern string, r io.RuneReader) (matched bool, error error)
|
||||
func MatchString(pattern string, s string) (matched bool, error error)
|
||||
|
||||
```
|
||||
All 3 functions check if `pattern` matches the input source, returning true if it matches. However if your Regex has syntax errors, it will return an error. The 3 input sources of these functions are `slice of byte`, `RuneReader` and `string`.
|
||||
|
||||
Here is an example of how to verify an IP address:
|
||||
|
||||
```Go
|
||||
func IsIP(ip string) (b bool) {
|
||||
if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
```
|
||||
As you can see, using pattern in the `regexp` package is not that different. Here's one more example on verifying whether user input is valid:
|
||||
|
||||
```Go
|
||||
func main() {
|
||||
if len(os.Args) == 1 {
|
||||
fmt.Println("Usage: regexp [string]")
|
||||
@@ -38,7 +38,7 @@ As you can see, using pattern in the `regexp` package is not that different. Her
|
||||
fmt.Println("Not number")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
In the above examples, we use `Match(Reader|String)` to check if content is valid, but they are all easy to use.
|
||||
|
||||
## Filter
|
||||
@@ -46,7 +46,7 @@ In the above examples, we use `Match(Reader|String)` to check if content is vali
|
||||
Match mode can verify content but it cannot cut, filter or collect data from it. If you want to do that, you have to use the complex mode of Regexp.
|
||||
|
||||
Let's say we need to write a crawler. Here is an example for when you must use Regexp to filter and cut data.
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -93,20 +93,20 @@ Let's say we need to write a crawler. Here is an example for when you must use R
|
||||
|
||||
fmt.Println(strings.TrimSpace(src))
|
||||
}
|
||||
|
||||
```
|
||||
In this example, we use Compile as the first step for complex mode. It verifies that your Regex syntax is correct, then returns a `Regexp` for parsing content in other operations.
|
||||
|
||||
Here are some functions to parse your Regexp syntax:
|
||||
|
||||
```Go
|
||||
func Compile(expr string) (*Regexp, error)
|
||||
func CompilePOSIX(expr string) (*Regexp, error)
|
||||
func MustCompile(str string) *Regexp
|
||||
func MustCompilePOSIX(str string) *Regexp
|
||||
|
||||
```
|
||||
The difference between `ComplePOSIX` and `Compile` is that the former has to use POSIX syntax which is leftmost longest search, and the latter is only leftmost search. For instance, for Regexp `[a-z]{2,4}` and content `"aa09aaa88aaaa"`, `CompilePOSIX` returns `aaaa` but `Compile` returns `aa`. `Must` prefix means panic when the Regexp syntax is not correct, returning error otherwise.
|
||||
|
||||
Now that we know how to create a new Regexp, let's see how the methods provided by this struct can help us to operate on content:
|
||||
|
||||
```Go
|
||||
func (re *Regexp) Find(b []byte) []byte
|
||||
func (re *Regexp) FindAll(b []byte, n int) [][]byte
|
||||
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
|
||||
@@ -125,9 +125,9 @@ Now that we know how to create a new Regexp, let's see how the methods provided
|
||||
func (re *Regexp) FindStringSubmatchIndex(s string) []int
|
||||
func (re *Regexp) FindSubmatch(b []byte) [][]byte
|
||||
func (re *Regexp) FindSubmatchIndex(b []byte) []int
|
||||
|
||||
```
|
||||
These 18 methods include identical functions for different input sources (byte slice, string and io.RuneReader), so we can really simplify this list by ignoring input sources as follows:
|
||||
|
||||
```Go
|
||||
func (re *Regexp) Find(b []byte) []byte
|
||||
func (re *Regexp) FindAll(b []byte, n int) [][]byte
|
||||
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
|
||||
@@ -136,9 +136,9 @@ These 18 methods include identical functions for different input sources (byte s
|
||||
func (re *Regexp) FindIndex(b []byte) (loc []int)
|
||||
func (re *Regexp) FindSubmatch(b []byte) [][]byte
|
||||
func (re *Regexp) FindSubmatchIndex(b []byte) []int
|
||||
|
||||
```
|
||||
Code sample:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -192,31 +192,31 @@ Code sample:
|
||||
submatchallindex := re2.FindAllSubmatchIndex([]byte(a), -1)
|
||||
fmt.Println(submatchallindex)
|
||||
}
|
||||
|
||||
```
|
||||
As we've previously mentioned, Regexp also has 3 methods for matching. They do the exact same thing as the exported functions. In fact, those exported functions actually call these methods under the hood:
|
||||
|
||||
```Go
|
||||
func (re *Regexp) Match(b []byte) bool
|
||||
func (re *Regexp) MatchReader(r io.RuneReader) bool
|
||||
func (re *Regexp) MatchString(s string) bool
|
||||
|
||||
```
|
||||
Next, let's see how to replace strings using Regexp:
|
||||
|
||||
```Go
|
||||
func (re *Regexp) ReplaceAll(src, repl []byte) []byte
|
||||
func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte
|
||||
func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte
|
||||
func (re *Regexp) ReplaceAllLiteralString(src, repl string) string
|
||||
func (re *Regexp) ReplaceAllString(src, repl string) string
|
||||
func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string
|
||||
|
||||
```
|
||||
These are used in the crawling example, so we will not explain any further here.
|
||||
|
||||
Let's take a look at the definition of `Expand`:
|
||||
|
||||
```Go
|
||||
func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte
|
||||
func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte
|
||||
|
||||
```
|
||||
So how do we use `Expand`?
|
||||
|
||||
```Go
|
||||
func main() {
|
||||
src := []byte(`
|
||||
call hello alice
|
||||
@@ -230,7 +230,7 @@ So how do we use `Expand`?
|
||||
}
|
||||
fmt.Println(string(res))
|
||||
}
|
||||
|
||||
```
|
||||
At this point, you've learnt the whole `regexp` package in Go. I hope that you can understand more by studying examples of key methods, so that you can do something interesting on your own.
|
||||
|
||||
## Links
|
||||
|
||||
58
en/07.4.md
58
en/07.4.md
@@ -16,14 +16,14 @@ Most of the content that web applications respond to clients with is static, and
|
||||
In Go, we have the `template` package to help handle templates. We can use functions like `Parse`, `ParseFile` and `Execute` to load templates from plain text or files, then evaluate the dynamic parts, as shown in figure 7.1.
|
||||
|
||||
Example:
|
||||
|
||||
```Go
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
t := template.New("some template") // Create a template.
|
||||
t, _ = t.ParseFiles("tmpl/welcome.html", nil) // Parse template file.
|
||||
user := GetUser() // Get current user infomration.
|
||||
t.Execute(w, user) // merge.
|
||||
}
|
||||
|
||||
```
|
||||
As you can see, it's very easy to use, load and render data in templates in Go, just as in other programming languages.
|
||||
|
||||
For the sake of convenience, we will use the following rules in our examples:
|
||||
@@ -39,7 +39,7 @@ We've just shown you how to parse and render templates. Let's take it one step f
|
||||
### Fields
|
||||
|
||||
In Go, Every field that you intend to be rendered within a template should be put inside of `{{}}`. `{{.}}` is shorthand for the current object, which is similar to its Java or C++ counterpart. If you want to access the fields of the current object, you should use `{{.FieldName}}`. Notice that only exported fields can be accessed in templates. Here is an example:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -57,16 +57,16 @@ In Go, Every field that you intend to be rendered within a template should be pu
|
||||
p := Person{UserName: "Astaxie"}
|
||||
t.Execute(os.Stdout, p)
|
||||
}
|
||||
|
||||
```
|
||||
The above example outputs `hello Astaxie` correctly, but if we modify our struct a little bit, the following error emerges:
|
||||
|
||||
```Go
|
||||
type Person struct {
|
||||
UserName string
|
||||
email string // Field is not exported.
|
||||
}
|
||||
|
||||
t, _ = t.Parse("hello {{.UserName}}! {{.email}}")
|
||||
|
||||
```
|
||||
This part of the code will not be compiled because we try to access a field that has not been exported. However, if we try to use a field that does not exist, Go simply outputs an empty string instead of an error.
|
||||
|
||||
If you print `{{.}}` in a template, Go outputs a formatted string of this object, calling `fmt` under the covers.
|
||||
@@ -79,7 +79,7 @@ We know how to output a field now. What if the field is an object, and it also h
|
||||
- {% raw %}`{{with}}`{% endraw %} lets you write the same object name once and use `.` as shorthand for it ( ***Similar to `with` in VB*** ).
|
||||
|
||||
More examples:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -116,11 +116,11 @@ More examples:
|
||||
Friends: []*Friend{&f1, &f2}}
|
||||
t.Execute(os.Stdout, p)
|
||||
}
|
||||
|
||||
```
|
||||
### Conditions
|
||||
|
||||
If you need to check for conditions in templates, you can use the `if-else` syntax just like you do in regular Go programs. If the pipeline is empty, the default value of `if` is `false`. The following example shows how to use `if-else` in templates:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -141,7 +141,7 @@ If you need to check for conditions in templates, you can use the `if-else` synt
|
||||
tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if part {{else}} else part.{{end}}\n"))
|
||||
tIfElse.Execute(os.Stdout, nil)
|
||||
}
|
||||
|
||||
```
|
||||
As you can see, it's easy to use `if-else` in templates.
|
||||
|
||||
**Attention** You CANNOT use conditional expressions in if, for instance `.Mail=="astaxie@gmail.com"`. Only boolean values are acceptable.
|
||||
@@ -183,7 +183,7 @@ Suppose we have an `emailDeal` template function associated with its `EmailDealW
|
||||
func EmailDealWith(args …interface{}) string
|
||||
|
||||
Example:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -241,9 +241,9 @@ Example:
|
||||
Friends: []*Friend{&f1, &f2}}
|
||||
t.Execute(os.Stdout, p)
|
||||
}
|
||||
|
||||
```
|
||||
Here is a list of built-in template functions:
|
||||
|
||||
```Go
|
||||
var builtins = FuncMap{
|
||||
"and": and,
|
||||
"call": call,
|
||||
@@ -259,11 +259,11 @@ Here is a list of built-in template functions:
|
||||
"urlquery": URLQueryEscaper,
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
## Must
|
||||
|
||||
The template package has a function called `Must` which is for validating templates, like the matching of braces, comments, and variables. Let's take a look at an example of `Must`:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -283,7 +283,7 @@ The template package has a function called `Must` which is for validating templa
|
||||
tErr := template.New("check parse error with Must")
|
||||
template.Must(tErr.Parse(" some static text {{ .Name }"))
|
||||
}
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
The first one parsed OK.
|
||||
@@ -304,7 +304,7 @@ The sub-template is called using the following syntax:
|
||||
Here's a complete example, supposing that we have the following three files: `header.tmpl`, `content.tmpl` and `footer.tmpl` in the folder `templates`, we will read the folder and store the file names in a string array, which we will then use to parse files.
|
||||
|
||||
Main template:
|
||||
|
||||
```html
|
||||
{% raw %}
|
||||
//header.tmpl
|
||||
{{define "header"}}
|
||||
@@ -336,8 +336,9 @@ Main template:
|
||||
//otherwise the compiler wouldn't understand what to substitute when it reads the {{template "header"}}
|
||||
|
||||
{% endraw %}
|
||||
```
|
||||
Code:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -375,7 +376,7 @@ Code:
|
||||
fmt.Println()
|
||||
s3.Execute(os.Stdout, nil)
|
||||
}
|
||||
|
||||
```
|
||||
Here we can see that `template.ParseFiles` parses all nested templates into cache, and that every template defined by `{{define}}` are independent of each other. They are persisted in something like a map, where the template names are keys and the values are the template bodies. We can then use `ExecuteTemplate` to execute the corresponding sub-templates, so that the header and footer are independent and content contains them both. Note that if we try to execute `s1.Execute`, nothing will be outputted because there is no default sub-template available.
|
||||
|
||||
When you don't want to use `{{define}}`, then you can just create a text file with the name of the sub template, for instance `_head.tmpl` is a sub template which you'll use across your project then create this file in the templates folder, and use the normal syntax. Lookup cache is basically created so that you don't read the file every time you serve a request, because if you do, then you are wasting a lot of resources for reading a file which won't change unless the codebase is being rewritten, it doesn't make sense to parse the template files during each HTTP GET request, so the technique is used where we parse the files once and then do a `LookUp()` on the cache to execute the template when we need it to display data.
|
||||
@@ -383,23 +384,24 @@ When you don't want to use `{{define}}`, then you can just create a text file wi
|
||||
Templates in one set know each other, but you must parse them for every single set.
|
||||
|
||||
Some times you want to contextualize templates, for instance you have a `_head.html`, you might have a header who's value you have to populate based on which data you are loading for instance for a todo list manager you can have three categories `pending`, `completed`, `deleted`. for this suppose you have an if statement like this
|
||||
|
||||
```html
|
||||
<title>{{if eq .Navigation "pending"}} Tasks
|
||||
{{ else if eq .Navigation "completed"}}Completed
|
||||
{{ else if eq .Navigation "deleted"}}Deleted
|
||||
{{ else if eq .Navigation "edit"}} Edit
|
||||
{{end}}
|
||||
</title>
|
||||
|
||||
```
|
||||
Note: Go templates follow the Polish notation while performing the comparison where you give the operator first and the comparison value and the value to be compared with. The else if part is pretty straight forward
|
||||
|
||||
Typically we use a `{{ range }}` operator to loop through the context variable which we pass to the template while execution like this:
|
||||
|
||||
```Go
|
||||
//present in views package
|
||||
context := db.GetTasks("pending") //true when you want non deleted notes
|
||||
homeTemplate.Execute(w, context)
|
||||
```
|
||||
We get the context object from the database as a struct object, the definition is as below
|
||||
|
||||
```Go
|
||||
//Task is the struct used to identify tasks
|
||||
type Task struct {
|
||||
Id int
|
||||
@@ -421,7 +423,7 @@ We get the context object from the database as a struct object, the definition i
|
||||
context = types.Context{Tasks: task, Navigation: status}
|
||||
|
||||
//This line is in the database package where the context is returned back to the view.
|
||||
|
||||
```
|
||||
We use the task array and the Navigation in our templates, we saw how we use the Navigation in the template,
|
||||
we'll see how we'll use the actual task array in our template.
|
||||
|
||||
@@ -431,14 +433,14 @@ content of Task. The below example is very important when it comes to looping th
|
||||
start with the Range operator, then we can give any member of that struct as `{{.Name}}`, my Task structure has a
|
||||
Title and a Content, (please note the capital T and C, they are exported names and they need to be capitalised unless you
|
||||
want to make them private).
|
||||
|
||||
```Go
|
||||
{{ range .Tasks }}
|
||||
{{ .Title }}
|
||||
{{ .Content }}
|
||||
{{ end }}
|
||||
|
||||
```
|
||||
This block of code will print each title and content of the Task array. Below is a full example from github.com/thewhitetulip/Tasks home.html template.
|
||||
|
||||
```html
|
||||
<div class="timeline">
|
||||
{{ if .Tasks}} {{range .Tasks}}
|
||||
<div class="note">
|
||||
@@ -455,7 +457,7 @@ This block of code will print each title and content of the Task array. Below is
|
||||
Create new task<button class="floating-action-icon-add" > here </button> </p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
12
en/07.5.md
12
en/07.5.md
@@ -23,7 +23,7 @@ In Go, most of the file operation functions are located in the `os` package. Her
|
||||
Removes multiple directories according to `path`. Directories will not be deleted if `path` is a single path.
|
||||
|
||||
Code sample:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -40,7 +40,7 @@ Code sample:
|
||||
}
|
||||
os.RemoveAll("astaxie")
|
||||
}
|
||||
|
||||
```
|
||||
## Files
|
||||
|
||||
### Create and open files
|
||||
@@ -83,7 +83,7 @@ Functions for writing files:
|
||||
Write a string to a file.
|
||||
|
||||
Code sample:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -104,7 +104,7 @@ Code sample:
|
||||
fout.Write([]byte("Just a test!\r\n"))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
### Read files
|
||||
|
||||
Functions for reading files:
|
||||
@@ -118,7 +118,7 @@ Functions for reading files:
|
||||
Read data from position `off` to `b`.
|
||||
|
||||
Code sample:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -143,7 +143,7 @@ Code sample:
|
||||
os.Stdout.Write(buf[:n])
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
### Delete files
|
||||
|
||||
Go uses the same function for removing files and directories:
|
||||
|
||||
40
en/07.6.md
40
en/07.6.md
@@ -9,7 +9,7 @@ The following functions are from the `strings` package. See the official documen
|
||||
- func Contains(s, substr string) bool
|
||||
|
||||
Check if string `s` contains string `substr`, returns a boolean value.
|
||||
|
||||
```Go
|
||||
fmt.Println(strings.Contains("seafood", "foo"))
|
||||
fmt.Println(strings.Contains("seafood", "bar"))
|
||||
fmt.Println(strings.Contains("seafood", ""))
|
||||
@@ -20,44 +20,44 @@ The following functions are from the `strings` package. See the official documen
|
||||
//false
|
||||
//true
|
||||
//true
|
||||
|
||||
```
|
||||
- func Join(a []string, sep string) string
|
||||
|
||||
Combine strings from slice with separator `sep`.
|
||||
|
||||
```Go
|
||||
s := []string{"foo", "bar", "baz"}
|
||||
fmt.Println(strings.Join(s, ", "))
|
||||
//Output:foo, bar, baz
|
||||
|
||||
```
|
||||
- func Index(s, sep string) int
|
||||
|
||||
Find index of `sep` in string `s`, returns -1 if it's not found.
|
||||
|
||||
```Go
|
||||
fmt.Println(strings.Index("chicken", "ken"))
|
||||
fmt.Println(strings.Index("chicken", "dmr"))
|
||||
//Output:4
|
||||
//-1
|
||||
|
||||
```
|
||||
- func Repeat(s string, count int) string
|
||||
|
||||
Repeat string `s` `count` times.
|
||||
|
||||
```Go
|
||||
fmt.Println("ba" + strings.Repeat("na", 2))
|
||||
//Output:banana
|
||||
|
||||
```
|
||||
- func Replace(s, old, new string, n int) string
|
||||
|
||||
Replace string `old` with string `new` in string `s`. `n` is the number of replacements. If n is less than 0, replace all instances.
|
||||
|
||||
```Go
|
||||
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
|
||||
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
|
||||
//Output:oinky oinky oink
|
||||
//moo moo moo
|
||||
|
||||
```
|
||||
- func Split(s, sep string) []string
|
||||
|
||||
Split string `s` with separator `sep` into a slice.
|
||||
|
||||
```Go
|
||||
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
|
||||
fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
|
||||
fmt.Printf("%q\n", strings.Split(" xyz ", ""))
|
||||
@@ -66,28 +66,28 @@ The following functions are from the `strings` package. See the official documen
|
||||
//["" "man " "plan " "canal panama"]
|
||||
//[" " "x" "y" "z" " "]
|
||||
//[""]
|
||||
|
||||
```
|
||||
- func Trim(s string, cutset string) string
|
||||
|
||||
Remove `cutset` of string `s` if it's leftmost or rightmost.
|
||||
|
||||
```Go
|
||||
fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
|
||||
Output:["Achtung"]
|
||||
|
||||
```
|
||||
- func Fields(s string) []string
|
||||
|
||||
Remove space items and split string with space into a slice.
|
||||
|
||||
```Go
|
||||
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
|
||||
//Output:Fields are: ["foo" "bar" "baz"]
|
||||
|
||||
```
|
||||
|
||||
## strconv
|
||||
|
||||
The following functions are from the `strconv` package. As usual, please see official documentation for more details:
|
||||
|
||||
- Append series, convert data to string, and append to current byte slice.
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -121,9 +121,9 @@ The following functions are from the `strconv` package. As usual, please see off
|
||||
e := strconv.Itoa(1023)
|
||||
fmt.Println(a, b, c, d, e)
|
||||
}
|
||||
|
||||
```
|
||||
- Parse series, convert strings to other types.
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -154,7 +154,7 @@ The following functions are from the `strconv` package. As usual, please see off
|
||||
}
|
||||
fmt.Println(a, b, c, d, e)
|
||||
}
|
||||
|
||||
```
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
|
||||
Reference in New Issue
Block a user