From 500dac03dd5334e0cee0a81b33f1b190940abc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AE=A1=E5=AE=9C=E5=B0=A7?= Date: Sat, 19 Nov 2016 00:25:51 +0800 Subject: [PATCH 01/32] Update ref.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 冲突解决 --- zh/ref.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/zh/ref.md b/zh/ref.md index 0f26439c..7b8e48e2 100644 --- a/zh/ref.md +++ b/zh/ref.md @@ -11,14 +11,5 @@ 7. [Network programming with Go](http://jan.newmarch.name/go/) 8. [setup-the-rails-application-for-internationalization](http://guides.rubyonrails.org/i18n.html#setup-the-rails-application-for-internationalization) 9. [The Cross-Site Scripting (XSS) FAQ](http://www.cgisecurity.com/xss-faq.html) -<<<<<<< HEAD -<<<<<<< fa439f692f31fa3d054eac849ea958f29c613b6e 10. [Network programming with Go](http://jan.newmarch.name/go) -11. [RESTFul](http://www.ruanyifeng.com/blog/2011/09/restful.html) -======= -10. [Network programming with Go](http://jan.newmarch.name/go) ->>>>>>> fix #378 -======= -10. [Network programming with Go](http://jan.newmarch.name/go) -11. [RESTFul](http://www.ruanyifeng.com/blog/2011/09/restful.html) ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa +11. [RESTful](http://www.ruanyifeng.com/blog/2011/09/restful.html) From dab03f4a841ba3043404bc00c17e08bb233655b3 Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 14:01:11 +0100 Subject: [PATCH 02/32] Fix unresolved conflicts in gitignore, readme and en-version of the book --- .gitignore | 4 ---- .gitignore.orig | 8 -------- README.md.orig | 46 ---------------------------------------------- en/13.5.md | 10 ---------- 4 files changed, 68 deletions(-) delete mode 100644 .gitignore.orig delete mode 100644 README.md.orig diff --git a/.gitignore b/.gitignore index b2eb862a..dfebd51a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,3 @@ pkg/* *.html *.exe -<<<<<<< HEAD -======= - ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa diff --git a/.gitignore.orig b/.gitignore.orig deleted file mode 100644 index b2eb862a..00000000 --- a/.gitignore.orig +++ /dev/null @@ -1,8 +0,0 @@ -*~ -pkg/* -*.html -*.exe -<<<<<<< HEAD -======= - ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa diff --git a/README.md.orig b/README.md.orig deleted file mode 100644 index af091edb..00000000 --- a/README.md.orig +++ /dev/null @@ -1,46 +0,0 @@ -# Multiple Language Versions -<<<<<<< HEAD -======= -* [English](en/) ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa -* [French](fr/) -* [Spanish](es/) -* [中文](zh/) -* [日本語](ja/) -* [Turkish](tr/) -* [Português - Brasil](pt-br/) -* [German](de/) -* [Русский](ru/) - -# Donate - -AliPay: alipay - -English Donate:[donate](http://beego.me/donate) - -## Community -QQ群:148647580 - -BBS:[http://golanghome.com/](http://golanghome.com/) - -## Acknowledgments - - - [四月份平民](https://plus.google.com/110445767383269817959) (review代码) - - [Hong Ruiqi](https://github.com/hongruiqi) (review代码) - - [BianJiang](https://github.com/border) (编写go开发工具Vim和Emacs的设置) - - [Oling Cat](https://github.com/OlingCat)(review代码) - - [Wenlei Wu](mailto:spadesacn@gmail.com)(提供一些图片展示) - - [polaris](https://github.com/polaris1119)(review书) - - [雨痕](https://github.com/qyuhen)(review第二章) - -<<<<<<< HEAD -======= -Translator: - - [LarryBattle](https://github.com/LarryBattle) ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa -## License -Book License: [CC BY-SA 3.0 License](http://creativecommons.org/licenses/by-sa/3.0/) - -Code License: [BSD 3-Clause License]() - - diff --git a/en/13.5.md b/en/13.5.md index c11d0bd8..e011b8b0 100644 --- a/en/13.5.md +++ b/en/13.5.md @@ -127,11 +127,7 @@ func (this *EditController) Get() { id, _ := strconv.Atoi(this.Ctx.Params[":id"]) this.Data["Post"] = models.GetBlog(id) this.Layout = "layout.tpl" -<<<<<<< HEAD - this.TplNames = "new.tpl" -======= this.TplNames = "edit.tpl" ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa } func (this *EditController) Post() { @@ -154,17 +150,11 @@ type DeleteController struct { } func (this *DeleteController) Get() { -<<<<<<< HEAD - id, _ := strconv.Atoi(this.Ctx.Params[":id"]) - this.Data["Post"] = models.DelBlog(id) - this.Ctx.Redirect(302, "/") -======= id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) blog := models.GetBlog(id) this.Data["Post"] = blog models.DelBlog(blog) this.Ctx.Redirect(302, "/") ->>>>>>> eead24cf064976b648de5826eab51880c803b0fa } ``` From b19cd5d8d3aa28fe22880778c485249e22ccfd07 Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 14:01:39 +0100 Subject: [PATCH 03/32] Add system and generated files to the .gitignore --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 4 ++++ 2 files changed, 4 insertions(+) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 557367ed970ed56d928b9b2c78d9ee0221d6e012..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK&2G~`5S~p_uoDRx0a7I{K7tfb2!vddGzCSXD5_B_L{YG7w{d0c$aa!K6e$Nz zJOO9^-vhyk2Y^T66lQ;d?ATmsg?6OfZ@l}>X7<~7*9!ooJ+f~BXaJyKp;#t)!oK`I~>IBN>fcUOf22w)5jB;McP!14kMdnw}{mTL=U z=m8YK2B+(#INviI2mCaL?BsBw70!vge{CQu+EF2xh7-Qaqo-a23UC+6D5(c3OhJv3p%i!KQ>_gsfY{N z2+S$KHFN2Hn_LSzmsD&4S)&yW=Dxy-bF)6dITjWRtm(QV$C^Y#@!$Am4LvuCtJR;R zuvT0@cV1CT<#M@H)-INw8iQbB#AZB-+GhBKJ-N1H3BPB?gQfo{2)sYOY3;hsq_17x z4E)%1eJ4zW?(ez29ZcH6$hV_?gO9i8+VP;TUFn6+7(;ue@9esfYq_2qzfe?FRn)$= zF`d@x^@?6=)MgcZ+GtcO`kmW%XEW`UqFlXRZ*4yw&R)NL_x{7jPoKYhWzz+M#~QOs z0+;X&9VW)u2z@W`kMNmt3-A&KX`$Ido+OrjImW4@n4D5R^-N>}QUR&JSyO=S4>}f# zO@VWcZ0o>^T>%h_*vt%l`oTbBbb(EQbB@@9MtCS94<+J?L3lW}>w?!5IOoX2fr!fo z5x-2t4TZ2@$MJPW2h!vyYpH-#Ag#a}f7IytzxDU~e>zA$Nd=?=|CIuy*fBb7oRT Date: Sat, 19 Nov 2016 14:08:01 +0100 Subject: [PATCH 04/32] Fix english 7.4 chapter preventing book to be built --- en/07.4.md | 56 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/en/07.4.md b/en/07.4.md index c645d7a2..8543f254 100644 --- a/en/07.4.md +++ b/en/07.4.md @@ -9,11 +9,11 @@ The following demonstrates the template mechanism: Figure 7.1 Template mechanism -Most of the content that web applications respond to clients with is static, and the dynamic parts are usually very small. For example, if you need to display a list users who have visited a page, only the user name would be dynamic. The style of the list remains the same. As you can see, templates are useful for reusing static content. +Most of the content that web applications respond to clients with is static, and the dynamic parts are usually very small. For example, if you need to display a list users who have visited a page, only the user name would be dynamic. The style of the list remains the same. As you can see, templates are useful for reusing static content. ## Templating in Go -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. +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: @@ -75,8 +75,8 @@ If you print `{{.}}` in a template, Go outputs a formatted string of this object We know how to output a field now. What if the field is an object, and it also has its own fields? How do we print them all in one loop? We can use `{{with …}}…{{end}}` and `{{range …}}{{end}}` for exactly that purpose. -- `{{range}}` just like range in Go. -- `{{with}}` lets you write the same object name once and use `.` as shorthand for it ( ***Similar to `with` in VB*** ). +- {% raw %}`{{range}}`{% endraw %} just like range in Go. +- {% raw %}`{{with}}`{% endraw %} lets you write the same object name once and use `.` as shorthand for it ( ***Similar to `with` in VB*** ). More examples: @@ -305,6 +305,7 @@ Here's a complete example, supposing that we have the following three files: `he Main template: +{% raw %} //header.tmpl {{define "header"}} @@ -330,10 +331,11 @@ Main template: {{end}} - - //When using subtemplating make sure that you have parsed each sub template file, + + //When using subtemplating make sure that you have parsed each sub template file, //otherwise the compiler wouldn't understand what to substitute when it reads the {{template "header"}} +{% endraw %} Code: package main @@ -344,9 +346,9 @@ Code: "io/ioutil" "text/template" ) - + var templates *template.Template - + func main() { var allFiles []string files, err := ioutil.ReadDir("./templates") @@ -359,13 +361,13 @@ Code: allFiles = append(allFiles, "./templates/"+filename) } } - + templates, err = template.ParseFiles(allFiles...) #parses all .tmpl files in the 'templates' folder - + s1, _ := templates.LookUp("header.tmpl") s1.ExecuteTemplate(os.Stdout, "header", nil) fmt.Println() - s2, _ := templates.LookUp("content.tmpl") + s2, _ := templates.LookUp("content.tmpl") s2.ExecuteTemplate(os.Stdout, "content", nil) fmt.Println() s3, _ := templates.LookUp("footer.tmpl") @@ -380,19 +382,19 @@ 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 +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 - {{if eq .Navigation "pending"}} Tasks + <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}} - + 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: - + //present in views package context := db.GetTasks("pending") //true when you want non deleted notes homeTemplate.Execute(w, context) @@ -412,31 +414,31 @@ We get the context object from the database as a struct object, the definition i Search string Message string } - + //present in database package var task []types.Task var context types.Context 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 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. - + Here in the `{{ if .Tasks }}` we first check if the Tasks field of our context object which we passed to the template while executing is empty or not. If it is not empty then we will range through that array to populate the title and content of Task. The below example is very important when it comes to looping through an array in a template, we 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). - - so {{ range .Tasks }} - {{ .Title }} - {{ .Content }} - {{ end }} - + + {{ 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. - +
{{ if .Tasks}} {{range .Tasks}}
From a91ae34cf055f0a45e030f1cf723be2cb728a69f Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 14:09:06 +0100 Subject: [PATCH 05/32] Fix japanese book missing src folder preventing book to be built --- ja/src | 1 - ja/src/.DS_Store | Bin 0 -> 6148 bytes ja/src/1.2/main.go | 13 +++++++++++++ ja/src/1.2/sqrt.go | 11 +++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) delete mode 120000 ja/src create mode 100644 ja/src/.DS_Store create mode 100644 ja/src/1.2/main.go create mode 100644 ja/src/1.2/sqrt.go diff --git a/ja/src b/ja/src deleted file mode 120000 index 9fc720a7..00000000 --- a/ja/src +++ /dev/null @@ -1 +0,0 @@ -../../ebook/src \ No newline at end of file diff --git a/ja/src/.DS_Store b/ja/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4d63beace0cee612b117b73fbb5af88423808527 GIT binary patch literal 6148 zcmeH~J!->15QX2^E(~r|rraiNz&XJp>=XC`DFSJN1A(O8qvy>}V8^P6urOo3#Su?<{=R%(-#@NztaugJM9hqp35)&OmWY4|h=2%) zfC#LJK%U~*A6E2CdK3{5fprk@??a=z_R^6WpALo?0jN8c!?=!Fg4(=5?WH4?6`Ixb zVAX0dhIl>NsjaT-r6V=lVKsbM-PwGKp;@-W8WWoJ5CstsfdzqW=98cQXZm0B|Dr{y z2#CO)5wP9qa+>*4b+-O`J+Hr1)z^bgjmsHsegc^IQT#v;<9_o6wU>@mR%rSW2n-4$ I@UH}Z06&8e+5i9m literal 0 HcmV?d00001 diff --git a/ja/src/1.2/main.go b/ja/src/1.2/main.go new file mode 100644 index 00000000..132c60a7 --- /dev/null +++ b/ja/src/1.2/main.go @@ -0,0 +1,13 @@ +// 章节 1.2 +// $GOPATH/src/mathapp/main.go + +package main + +import ( + "fmt" + "mymath" +) + +func main() { + fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2)) +} diff --git a/ja/src/1.2/sqrt.go b/ja/src/1.2/sqrt.go new file mode 100644 index 00000000..1d596053 --- /dev/null +++ b/ja/src/1.2/sqrt.go @@ -0,0 +1,11 @@ +// 章节 1.2 +// $GOPATH/src/mymath/sqrt.go +package mymath + +func Sqrt(x float64) float64 { + z := 0.0 + for i := 0; i < 1000; i++ { + z -= (z*z - x) / (2 * x) + } + return z +} From 5dea1d8b592231db5f9be24d344853c120191d17 Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 16:09:28 +0100 Subject: [PATCH 06/32] Temporary remove Japanese build files to trick git --- ja/build.go | 1 - ja/build.sh | 1 - 2 files changed, 2 deletions(-) delete mode 120000 ja/build.go delete mode 120000 ja/build.sh diff --git a/ja/build.go b/ja/build.go deleted file mode 120000 index 8228b893..00000000 --- a/ja/build.go +++ /dev/null @@ -1 +0,0 @@ -../../ebook/build.go \ No newline at end of file diff --git a/ja/build.sh b/ja/build.sh deleted file mode 120000 index a100c8e3..00000000 --- a/ja/build.sh +++ /dev/null @@ -1 +0,0 @@ -../../ebook/build.sh \ No newline at end of file From 58cfbca7ffd6eb5ff58088f9ca94b76bb7b851bd Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 16:10:24 +0100 Subject: [PATCH 07/32] Fix build by copying build files from English to Japanese version --- ja/build.go | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ja/build.sh | 56 +++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 ja/build.go create mode 100755 ja/build.sh diff --git a/ja/build.go b/ja/build.go new file mode 100644 index 00000000..fbf7e662 --- /dev/null +++ b/ja/build.go @@ -0,0 +1,118 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/fairlyblank/md2min" +) + +// 定义一个访问者结构体 +type Visitor struct{} + +func (self *Visitor) md2html(arg map[string]string) error { + from := arg["from"] + to := arg["to"] + err := filepath.Walk(from+"/", func(path string, f os.FileInfo, err error) error { + if f == nil { + return err + } + if f.IsDir() { + return nil + } + if (f.Mode() & os.ModeSymlink) > 0 { + return nil + } + if !strings.HasSuffix(f.Name(), ".md") { + return nil + } + + file, err := os.Open(path) + if err != nil { + return err + } + + input_byte, _ := ioutil.ReadAll(file) + input := string(input_byte) + input = regexp.MustCompile(`\[(.*?)\]\(?\)`).ReplaceAllString(input, "[$1](<$2.html>)") + + if f.Name() == "README.md" { + input = regexp.MustCompile(`https:\/\/github\.com\/astaxie\/build-web-application-with-golang\/blob\/master\/`).ReplaceAllString(input, "") + } + + // 以#开头的行,在#后增加空格 + // 以#开头的行, 删除多余的空格 + input = FixHeader(input) + + // 删除页面链接 + input = RemoveFooterLink(input) + + // remove image suffix + input = RemoveImageLinkSuffix(input) + + var out *os.File + filename := strings.Replace(f.Name(), ".md", ".html", -1) + fmt.Println(to + "/" + filename) + if out, err = os.Create(to + "/" + filename); err != nil { + fmt.Fprintf(os.Stderr, "Error creating %s: %v", f.Name(), err) + os.Exit(-1) + } + defer out.Close() + md := md2min.New("none") + err = md.Parse([]byte(input), out) + if err != nil { + fmt.Fprintln(os.Stderr, "Parsing Error", err) + os.Exit(-1) + } + + return nil + }) + return err +} + +func FixHeader(input string) string { + re_header := regexp.MustCompile(`(?m)^#.+$`) + re_sub := regexp.MustCompile(`^(#+)\s*(.+)$`) + fixer := func(header string) string { + s := re_sub.FindStringSubmatch(header) + return s[1] + " " + s[2] + } + return re_header.ReplaceAllStringFunc(input, fixer) +} + +func RemoveFooterLink(input string) string { + re_footer := regexp.MustCompile(`(?m)^#{2,} links.*?\n(.+\n)*`) + return re_footer.ReplaceAllString(input, "") +} + +func RemoveImageLinkSuffix(input string) string { + re_footer := regexp.MustCompile(`png\?raw=true`) + return re_footer.ReplaceAllString(input, "png") +} + +func main() { + tmp := os.Getenv("TMP") + if tmp == "" { + tmp = "." + } + + workdir := os.Getenv("WORKDIR") + if workdir == "" { + workdir = "." + } + + arg := map[string]string{ + "from": workdir, + "to": tmp, + } + + v := &Visitor{} + err := v.md2html(arg) + if err != nil { + fmt.Printf("filepath.Walk() returned %v\n", err) + } +} diff --git a/ja/build.sh b/ja/build.sh new file mode 100755 index 00000000..4f4f7a76 --- /dev/null +++ b/ja/build.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +SED='sed' + +if [ `uname -s` == 'Darwin' ] ; then + SED='gsed' +fi + +bn="`basename $0`" +WORKDIR="$(cd $(dirname $0); pwd -P)" + +# +# Default language: zh +# You can overwrite following variables in config file. +# +MSG_INSTALL_PANDOC_FIRST='请先安装pandoc,然后再次运行' +MSG_SUCCESSFULLY_GENERATED='build-web-application-with-golang.epub 已经建立' +MSG_CREATOR='Astaxie' +MSG_DESCRIPTION='一本开源的Go Web编程书籍' +MSG_LANGUAGE='zh-CN' +MSG_TITLE='Go Web编程' +[ -e "$WORKDIR/config" ] && . "$WORKDIR/config" + + +TMP=`mktemp -d 2>/dev/null || mktemp -d -t "${bn}"` || exit 1 +trap 'rm -rf "$TMP"' 0 1 2 3 15 + + +cd "$TMP" + +( +[ go list github.com/fairlyblank/md2min >/dev/null 2>&1 ] || export GOPATH="$PWD" +go get -u github.com/fairlyblank/md2min +WORKDIR="$WORKDIR" TMP="$TMP" go run "$WORKDIR/build.go" +) + +if [ ! type -P pandoc >/dev/null 2>&1 ]; then + echo "$MSG_INSTALL_PANDOC_FIRST" + exit 0 +fi + +cat <<__METADATA__ > metadata.txt +$MSG_CREATOR +$MSG_DESCRIPTION +$MSG_LANGUAGE +Creative Commons +$MSG_TITLE +__METADATA__ + +mkdir -p $TMP/images +cp -r $WORKDIR/images/* $TMP/images/ +ls [0-9]*.html | xargs $SED -i "s/png?raw=true/png/g" + +pandoc --reference-links -S --toc -f html -t epub --epub-metadata=metadata.txt --epub-cover-image="$WORKDIR/images/cover.png" -o "$WORKDIR/../build-web-application-with-golang.epub" `ls [0-9]*.html | sort` + +echo "$MSG_SUCCESSFULLY_GENERATED" From 1b85586e22df8f38058c0cf293195c186346ba6e Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 16:37:09 +0100 Subject: [PATCH 08/32] Fix failing build for a Japanese version because of template tags --- ja/04.3.md | 2 ++ ja/04.5.md | 4 +++- ja/06.4.md | 2 ++ ja/07.1.md | 2 ++ ja/07.4.md | 2 ++ ja/09.1.md | 2 ++ ja/10.2.md | 2 ++ ja/10.3.md | 2 ++ ja/12.2.md | 18 ++++++++++-------- ja/13.3.md | 42 ++++++++++++++++++++++-------------------- ja/13.5.md | 50 ++++++++++++++++++++++++++------------------------ ja/14.3.md | 14 ++++++++------ ja/14.5.md | 36 +++++++++++++++++++----------------- 13 files changed, 102 insertions(+), 76 deletions(-) diff --git a/ja/04.3.md b/ja/04.3.md index f8818f8c..78cf119b 100644 --- a/ja/04.3.md +++ b/ja/04.3.md @@ -1,3 +1,4 @@ +{% raw %} # 4.3 クロスサイトスクリプティングの予防 現在のホームページは大量の動的なコンテンツを含みユーザのエクスペリエンスを高めています。以前に比べてとても複雑になっています。いわゆる動的なコンテンツとはユーザの環境と要求に応じてWebアプリケーションが目的の内容を出力できることを指します。動的なホームページは"クロスサイトスクリプティング"(Cross Site Scripting、セキュリティ専門家が一般的にXSSと省略するもの)と呼ばれる攻撃を受けることがあります。 @@ -66,3 +67,4 @@ Goのhtml/templateパッケージはデフォルトでhtmlタグをフィルタ * [目次]() * 前へ: [入力値の検証](<04.2.md>) * 次へ: [フォームの複数回送信の防止](<04.4.md>) +{% endraw %} diff --git a/ja/04.5.md b/ja/04.5.md index 7bf16234..c02357e6 100644 --- a/ja/04.5.md +++ b/ja/04.5.md @@ -1,3 +1,4 @@ +{% raw %} # 4.5 ファイルのアップロード処理 ユーザによるファイルのアップロードを処理したいとします。例えば、現在Instagramのようなホームページを作成しているとします。ユーザが撮影した写真を保存する必要があります。このような要求はどのように実現するのでしょうか? @@ -115,7 +116,7 @@ return err } defer fh.Close() - + //iocopy _, err = io.Copy(fileWriter, fh) if err != nil { @@ -155,3 +156,4 @@ * [目次]() * 前へ: [フォームの多重送信の防止](<04.4.md>) * 次へ: [まとめ](<04.6.md>) +{% endraw %} diff --git a/ja/06.4.md b/ja/06.4.md index 312bbae8..5f001b46 100644 --- a/ja/06.4.md +++ b/ja/06.4.md @@ -1,3 +1,4 @@ +{% raw %} # 6.4 sessionハイジャックの予防 sessionハイジャックは広範囲に存在する比較的重大な脆弱性です。session技術において、クライアントサイドとサーバサイドはsessionのIDによってセッションを維持します。しかしこのIDは簡単にスニッフィングされ、第三者に利用されてしまいます。これは中間者攻撃の一種です。 @@ -87,3 +88,4 @@ sessionが始まると、生成されたsessionIDの時間を記録する一つ * [目次]() * 前へ: [sessionストレージ](<06.3.md>) * 次へ: [まとめ](<06.5.md>) +{% endraw %} diff --git a/ja/07.1.md b/ja/07.1.md index 29424aee..1ca83bfd 100644 --- a/ja/07.1.md +++ b/ja/07.1.md @@ -1,3 +1,4 @@ +{% raw %} # 7.1 XMLの処理 XMLはデータと情報のやりとりするための形式として十分普及しています。Webサービスが日々広範囲で応用されてくるにつれ、現在XMLは日常的な開発作業において重要な役割を演じてきました。この節ではGo言語の標準パッケージにあるXML関連のパッケージをご紹介します。 @@ -219,3 +220,4 @@ XMLをstructに解析する際は以下のルールに従います:  * [目次]() * 前へ: [テキスト処理](<07.0.md>) * 次へ: [Jsonの処理](<07.2.md>) +{% endraw %} diff --git a/ja/07.4.md b/ja/07.4.md index 61e95da3..9f5f7150 100644 --- a/ja/07.4.md +++ b/ja/07.4.md @@ -1,3 +1,4 @@ +{% raw %} # 7.4 テンプレートの処理 ## テンプレートとは何か おそらくあなたはMVCのデザインパターンについて聞いたことがあると思います。Modelはデータを処理を、Viewは表示結果を、Controllerはユーザのリクエストの制御を行います。Viewレイヤーの処理では、多くの動的な言語ではどれも静的なHTMLの中に動的言語が生成したデータを挿入します。例えばJSPでは`<%=....=%>`を挿入することで、PHPでは``を挿入することで実現します。 @@ -348,3 +349,4 @@ Webアプリケーションを作る時はテンプレートの一部が固定 * [目次]() * 前へ: [正規表現の処理](<07.3.md>) * 次へ: [ファイルの操作](<07.5.md>) +{% endraw %} diff --git a/ja/09.1.md b/ja/09.1.md index 25ef0df6..74c30a45 100644 --- a/ja/09.1.md +++ b/ja/09.1.md @@ -1,3 +1,4 @@ +{% raw %} # 9.1 CSRF攻撃の予防 ## CSRFとは何か  @@ -91,3 +92,4 @@ tokenを検証 * [目次]() * 前へ: [セキュリティと暗号化](<09.0.md>) * 次へ: [入力フィルタリングの確保](<09.2.md>) +{% endraw %} diff --git a/ja/10.2.md b/ja/10.2.md index e693acb2..c761e099 100644 --- a/ja/10.2.md +++ b/ja/10.2.md @@ -1,3 +1,4 @@ +{% raw %} # 10.2 ローカライズリソース 前の節ではどのようにしてLocaleを設定するかご紹介しました。Localeを設定したあとはどのようにしてLocaleに対応する情報を保存するかという問題を解決する必要があります。ここでの情報とは以下の内容を含みます:テキスト情報、時間と日時、通貨の値、画像、ファイルや動画といったリソース等です。ここではこれらの情報に対してご紹介していきたいと思います。Go言語ではこれらのフォーマットの情報をJSONに保存します。その後それぞれ適した方法によって表示します。(以下では日本語と英語の2つの言語を対比して例を挙げます。保存の形式はそれぞれen.jsonとja-JP.jsonです。) ## ローカライズテキスト情報 @@ -132,3 +133,4 @@ Localeの違いによってビューを表示させる場合もあるかもし * [目次]() * 前へ: [デフォルトロケールの設定](<10.1.md>) * 次へ: [国際化サイト](<10.3.md>) +{% endraw %} diff --git a/ja/10.3.md b/ja/10.3.md index dea1ecda..dfa7eaa1 100644 --- a/ja/10.3.md +++ b/ja/10.3.md @@ -1,3 +1,4 @@ +{% raw %} # 10.3 国際化サイト 前の節でどのようにしてローカライズリソースを処理するかご紹介しました。Localeに対応した設定ファイルです。ではもし複数のローカライズリソースを処理する場合は?いくつかの我々が通常使用する例は:簡単なテキスト翻訳、時間や日時、数字といったものはどのように処理するのでしょうか?この節では一つ一つこれらの問題を解決していきます。 ## 複数のロケールパッケージの管理 @@ -178,3 +179,4 @@ * [目次]() * 前へ: [ローカライズリソース](<10.2.md>) * 次へ: [まとめ](<10.4.md>) +{% endraw %} diff --git a/ja/12.2.md b/ja/12.2.md index 3e1c0d05..f186ac0f 100644 --- a/ja/12.2.md +++ b/ja/12.2.md @@ -1,8 +1,9 @@ +{% raw %} # 12.2 サイトエラー処理 我々のWebアプリケーションが一旦実運用されると、さまざまなエラーが発生する可能性があります。Webアプリケーションの日常の実行ではいくつものエラーが発生する可能性があります。具体的には以下のとおり: - データベースエラー:データベースサーバへのアクセスまたはデータと関係のあるエラーです。例えば、以下は何らかのデータベースエラーを発生させることがあります。 - + - 接続エラー:このエラーはデータベースサーバのネットワークが切断された時や、ユーザ名とパスワードが不正だった場合、またはデータベースが存在しない場合に発生することがあります。 - 検索エラー:使用されたSQLが正しく無く、エラーが発生する場合です。このようなSQLエラーはもしプログラムに厳格なテストを行うことで回避できます。 - データエラー:データベースの約束が衝突する場合。例えば一つしかないフィールドに複数の主キーを持つデータが挿入されるとエラーを発生させます。しかし、あなたのアプリケーションプログラムが運用される前に厳格なテストを行うことでこれらの問題を回避することもできます。 @@ -27,9 +28,9 @@ エラー処理は実は我々も第十一章の第一節でどのようにエラー処理を設計するかご紹介しました。ここではまたひとつの例から詳細にご解説します。どのように異なるエラーを処理するのでしょうか: - ユーザにエラーが発生したことを通知する: - + ユーザがページにアクセスした時はふたつのエラーがあります:404.htmlとerror.htmlです。以下はそれぞれエラーページを表示するソースです: - + @@ -51,7 +52,7 @@ もうひとつのソース: - + @@ -72,9 +73,9 @@
- + 404のエラー処理ロジック、もしシステムのエラーだった場合もにたような操作になります。以下を見てみましょう: - + func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { sayhelloName(w, r) @@ -90,7 +91,7 @@ ErrorInfo := "ファイルが見つかりません" //現在のユーザ情報を取得 t.Execute(w, ErrorInfo) //テンプレートのmerger操作を実行 } - + func SystemError(w http.ResponseWriter, r *http.Request) { log.Critical("システムエラー") //システムエラーはクリティカルですので、ログに記録するだけでなくメールを送信します。 t, _ = t.ParseFiles("tmpl/error.html", nil) //テンプレートファイルを解析 @@ -109,7 +110,7 @@ username = "" } }() - + username = User[uid] return } @@ -122,3 +123,4 @@ * [目次]() * 前へ: [アプリケーションログ](<12.1.md>) * 次へ: [アプリケーションのデプロイ](<12.3.md>) +{% endraw %} diff --git a/ja/13.3.md b/ja/13.3.md index 9e1e1458..5526c9a8 100644 --- a/ja/13.3.md +++ b/ja/13.3.md @@ -1,3 +1,4 @@ +{% raw %} # 13.3 controller設計 伝統的なMVCフレームワークにおいて、多くの場合Action設計のサフィックス反映にもとづいています、しかしながら、現在webではREST風のフレームワークが流行しています。なるべくFilterかrewriteを使用してURLのリライトを行い、REST風のURLを実現しています。しかしなぜ直接新しくREST風のMVCフレームワークを設計しないのでしょうか?本章ではこういった考え方に基いてどのようにREST風のMVCフレームワークにフルスクラッチでcontroller、最大限に簡素化されたWebアプリケーションの開発、ひいては一行で可能な"Hello, world"の実装についてご説明します。 @@ -17,7 +18,7 @@ MVC設計は現在Webアプリケーションの開発において最もよく Layout []string TplExt string } - + type ControllerInterface interface { Init(ct *Context, cn string) //コンテキストとサブクラスの名前を初期化 Prepare() //実行前のいくつかの処理を開始 @@ -31,7 +32,7 @@ MVC設計は現在Webアプリケーションの開発において最もよく Finish() //実行完了後の処理 Render() error //methodが対応する方法を実行し終えた後、ページを構築 } - + 前にadd関数へのルータをご紹介した際ControllerInterfaceクラスを定義しました。ですので、ここではこのインターフェースを実装すれば十分です。基底クラスのContorollerの実装は以下のようなメソッドになります: func (c *Controller) Init(ct *Context, cn string) { @@ -42,43 +43,43 @@ MVC設計は現在Webアプリケーションの開発において最もよく c.Ct = ct c.TplExt = "tpl" } - + func (c *Controller) Prepare() { - + } - + func (c *Controller) Finish() { - + } - + func (c *Controller) Get() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Post() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Delete() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Put() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Head() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Patch() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Options() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Render() error { if len(c.Layout) > 0 { var filenames []string @@ -108,10 +109,10 @@ MVC設計は現在Webアプリケーションの開発において最もよく } return nil } - + func (c *Controller) Redirect(url string, code int) { c.Ct.Redirect(code, url) - } + } 上のcontroller基底クラスはインターフェースが定義する関数を実装しています。urlにもとづいてルータが対応するcontrollerを実行する原則に従って、以下のように実行されます: @@ -125,21 +126,21 @@ MVC設計は現在Webアプリケーションの開発において最もよく 上ではbeegoフレームワークにおいてcontroller基底クラスの設計を完成させました。我々のアプリケーションでは我々のメソッドを以下のように設計することができます: package controllers - + import ( "github.com/astaxie/beego" ) - + type MainController struct { beego.Controller } - + func (this *MainController) Get() { this.Data["Username"] = "astaxie" this.Data["Email"] = "astaxie@gmail.com" this.TplNames = "index.tpl" } - + 上のメソッドではサブクラスMainControllerを実装し、Getメソッドを実装しています。もしユーザがその他のメソッド(POST/HEAD等)によってこのリソースにアクセスすると、403を返します。もしGetであれば、AutoRender=trueを設定していますのでGetメソッドの実行後自動的にRender関数が実行され、以下のようなインターフェースが表示されます: ![](images/13.4.beego.png?raw=true) @@ -161,3 +162,4 @@ index.tplのコードは以下のようになります。データの設定と * [目次]() * 前へ: [カスタム定義のルータの設計](<13.2.md>) * 次へ: [ログとコンフィグ設計](<13.4.md>) +{% endraw %} diff --git a/ja/13.5.md b/ja/13.5.md index b465aee8..b18c68d7 100644 --- a/ja/13.5.md +++ b/ja/13.5.md @@ -1,3 +1,4 @@ +{% raw %} # 13.5 ブログの追加/削除/修正の実装 前ではbeegoフレームワークの全体的な構造思想の実装とニセコードの一部の実装についてご紹介しました。この節ではbeegoを通してブログシステムを設計しましょう。これにはブログの閲覧、追加、修正、削除といった操作が含まれます。 @@ -52,19 +53,19 @@ IndexController: type IndexController struct { beego.Controller } - + func (this *IndexController) Get() { this.Data["blogs"] = models.GetAll() this.Layout = "layout.tpl" this.TplNames = "index.tpl" } - + ViewController: type ViewController struct { beego.Controller } - + func (this *ViewController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) this.Data["Post"] = models.GetBlog(id) @@ -77,12 +78,12 @@ NewController type NewController struct { beego.Controller } - + func (this *NewController) Get() { this.Layout = "layout.tpl" this.TplNames = "new.tpl" } - + func (this *NewController) Post() { inputs := this.Input() var blog models.Blog @@ -98,14 +99,14 @@ EditController type EditController struct { beego.Controller } - + func (this *EditController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) this.Data["Post"] = models.GetBlog(id) this.Layout = "layout.tpl" this.TplNames = "edit.tpl" } - + func (this *EditController) Post() { inputs := this.Input() var blog models.Blog @@ -116,39 +117,39 @@ EditController models.SaveBlog(blog) this.Ctx.Redirect(302, "/") } - + DeleteController type DeleteController struct { beego.Controller } - + func (this *DeleteController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) blog := models.GetBlog(id) this.Data["Post"] = blog models.DelBlog(blog) this.Ctx.Redirect(302, "/") - } + } ## modelレイヤ package models - + import ( "database/sql" "github.com/astaxie/beedb" _ "github.com/ziutek/mymysql/godrv" "time" ) - + type Blog struct { Id int `PK` Title string Content string Created time.Time } - + func GetLink() beedb.Model { db, err := sql.Open("mymysql", "blog/astaxie/123456") if err != nil { @@ -157,25 +158,25 @@ DeleteController orm := beedb.New(db) return orm } - + func GetAll() (blogs []Blog) { db := GetLink() db.FindAll(&blogs) return } - + func GetBlog(id int) (blog Blog) { db := GetLink() db.Where("id=?", id).Find(&blog) return } - + func SaveBlog(blog Blog) (bg Blog) { db := GetLink() db.Save(&blog) return bg } - + func DelBlog(blog Blog) { db := GetLink() db.Delete(&blog) @@ -198,17 +199,17 @@ layout.tpl - + - + {{.LayoutContent}} - + - + index.tpl

Blog posts

@@ -216,7 +217,7 @@ index.tpl
    {{range .blogs}}
  • - {{.Title}} + {{.Title}} from {{.Created}} Edit Delete @@ -228,7 +229,7 @@ view.tpl

    {{.Post.Title}}

    {{.Post.Created}}
    - + {{.Post.Content}} new.tpl @@ -241,7 +242,7 @@ new.tpl edit.tpl - +

    Edit {{.Post.Title}}

    New Blog Post

    @@ -256,3 +257,4 @@ edit.tpl * [目次]() * 前へ: [ログとコンフィグ設計](<13.4.md>) * 次へ: [まとめ](<13.6.md>) +{% endraw %} diff --git a/ja/14.3.md b/ja/14.3.md index 417ef079..12408378 100644 --- a/ja/14.3.md +++ b/ja/14.3.md @@ -1,3 +1,4 @@ +{% raw %} # 14.3 フォームおよび検証のサポート Web開発ではこのようなプロセスをよく見かけます: @@ -28,7 +29,7 @@ Web開発ではこのようなプロセスをよく見かけます: Email string `form:text,valid:required|valid_email` Introduce string `form:textarea` } - + structを定義したらcontrollerにおいてこのように操作します func (this *AddController) Get() { @@ -36,26 +37,26 @@ structを定義したらcontrollerにおいてこのように操作します this.Layout = "admin/layout.html" this.TplNames = "admin/add.tpl" } - + テンプレートで以下のようにフォームを表示します

    New Blog Post

    {{.form.render()}}
    - + 上では全体の第1ステップを定義しました。structからフォームを表示したあとは、ユーザが情報を入力し、サーバがデータを受け取って検証を行った後、データベースに保存されます。 func (this *AddController) Post() { var user User form := this.GetInput(&user) if !form.Validates() { - return + return } models.UserInsert(&user) this.Ctx.Redirect(302, "/admin/index") } - + ## フォームの型 以下のリストは対応するform要素の情報を表しています: @@ -121,7 +122,7 @@ structを定義したらcontrollerにおいてこのように操作します
    - + ## フォームの検証 以下のリストは使用されるオリジナルのルールを表しています @@ -279,3 +280,4 @@ structを定義したらcontrollerにおいてこのように操作します * [目次]() * 前へ: [Sessionのサポート](<14.2.md>) * 次へ: [ユーザの認証](<14.4.md>) +{% endraw %} diff --git a/ja/14.5.md b/ja/14.5.md index c1d7655b..a3e3cde0 100644 --- a/ja/14.5.md +++ b/ja/14.5.md @@ -1,3 +1,4 @@ +{% raw %} # 14.5 多言語サポート 第10章において国際化とローカライゼーションおよびgo-i18nライブラリの開発についてご紹介しました。この節ではこのライブラリをbeegoフレームワークの中にもってくることで、我々のフレームワークにおいて国際化とローカライゼーションをサポートさせます。 @@ -21,7 +22,7 @@ beegoにおいて以下のようにグローバル変数を設定します: beegoTplFuncMap["Trans"] = i18n.I18nT beegoTplFuncMap["TransDate"] = i18n.I18nTimeDate beegoTplFuncMap["TransMoney"] = i18n.I18nMoney - + func I18nT(args ...interface{}) string { ok := false var s string @@ -33,7 +34,7 @@ beegoにおいて以下のようにグローバル変数を設定します: } return beego.Translation.Translate(s) } - + func I18nTimeDate(args ...interface{}) string { ok := false var s string @@ -44,8 +45,8 @@ beegoにおいて以下のようにグローバル変数を設定します: s = fmt.Sprint(args...) } return beego.Translation.Time(s) - } - + } + func I18nMoney(args ...interface{}) string { ok := false var s string @@ -60,7 +61,7 @@ beegoにおいて以下のようにグローバル変数を設定します: ## 多言語開発の使用 1. 言語および言語パッケージのパスを設定します。その後i18nオブジェクトを初期化します: - + beego.Lang = "zh" beego.LangPath = "views/lang" beego.InitLang() @@ -68,18 +69,18 @@ beegoにおいて以下のようにグローバル変数を設定します: 2. 多言語パッケージの設計 上ではどのようにして多言語パッケージを初期化するかについてご紹介しました。今から多言語パッケージを設計します。多言語パッケージはjsonファイルです。第10章でご紹介したのと同じように、設計する必要のあるファイルをLangPathの下に置きます。例えばzh.jsonまたはen.jsonといったものです。 - + # zh.json - + { "zh": { "submit": "送信", "create": "新規作成" } } - + #en.json - + { "en": { "submit": "Submit", @@ -90,24 +91,25 @@ beegoにおいて以下のようにグローバル変数を設定します: 3. 多言語パッケージを使用する controllerの中でコンパイラをコールして対応する翻訳言語を取得することができます。以下に示します: - + func (this *MainController) Get() { this.Data["create"] = beego.Translation.Translate("create") this.TplNames = "index.tpl" } - + テンプレートの中で直接対応する翻訳関数をコールしてもかまいません: - + //直接テキスト翻訳 {{.create | Trans}} - + //時間の翻訳 - {{.time | TransDate}} - + {{.time | TransDate}} + //通貨の翻訳 - {{.money | TransMoney}} - + {{.money | TransMoney}} + ## links * [目次]() * 前へ: [ユーザ認証](<14.4.md>) * 次へ: [pprofのサポート](<14.6.md>) +{% endraw %} From 1e5131b5c7f6c23f2363ff9fbb69ebb215d3f5cd Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 16:40:48 +0100 Subject: [PATCH 09/32] Fix failing build for a Chinese version because of template tags --- zh/09.1.md | 2 ++ zh/10.2.md | 2 ++ zh/10.3.md | 2 ++ zh/12.2.md | 18 ++++++++++-------- zh/13.3.md | 42 ++++++++++++++++++++++-------------------- zh/13.5.md | 50 ++++++++++++++++++++++++++------------------------ zh/14.3.md | 16 +++++++++------- zh/14.5.md | 38 ++++++++++++++++++++------------------ 8 files changed, 93 insertions(+), 77 deletions(-) diff --git a/zh/09.1.md b/zh/09.1.md index 6f7c95af..e873bd95 100644 --- a/zh/09.1.md +++ b/zh/09.1.md @@ -1,3 +1,4 @@ +{% raw %} # 9.1 预防CSRF攻击 ## 什么是CSRF @@ -91,3 +92,4 @@ CSRF的防御可以从服务端和客户端两方面着手,防御效果是从 * [目录]() * 上一节: [安全与加密](<09.0.md>) * 下一节: [确保输入过滤](<09.2.md>) +{% endraw %} diff --git a/zh/10.2.md b/zh/10.2.md index 54e39903..b507e8f7 100644 --- a/zh/10.2.md +++ b/zh/10.2.md @@ -1,3 +1,4 @@ +{% raw %} # 10.2 本地化资源 前面小节我们介绍了如何设置Locale,设置好Locale之后我们需要解决的问题就是如何存储相应的Locale对应的信息呢?这里面的信息包括:文本信息、时间和日期、货币值、图片、包含文件以及视图等资源。那么接下来我们将对这些信息一一进行介绍,Go语言中我们把这些格式信息存储在JSON中,然后通过合适的方式展现出来。(接下来以中文和英文两种语言对比举例,存储格式文件en.json和zh-CN.json) ## 本地化文本消息 @@ -132,3 +133,4 @@ $GOROOT/lib/time包中的timeinfo.zip含有locale对应的时区的定义,为 * [目录]() * 上一节: [设置默认地区](<10.1.md>) * 下一节: [国际化站点](<10.3.md>) +{% endraw %} diff --git a/zh/10.3.md b/zh/10.3.md index a61185b1..00659ed9 100644 --- a/zh/10.3.md +++ b/zh/10.3.md @@ -1,3 +1,4 @@ +{% raw %} # 10.3 国际化站点 前面小节介绍了如何处理本地化资源,即Locale一个相应的配置文件,那么如果处理多个的本地化资源呢?而对于一些我们经常用到的例如:简单的文本翻译、时间日期、数字等如果处理呢?本小节将一一解决这些问题。 ## 管理多个本地包 @@ -178,3 +179,4 @@ * [目录]() * 上一节: [本地化资源](<10.2.md>) * 下一节: [小结](<10.4.md>) +{% endraw %} diff --git a/zh/12.2.md b/zh/12.2.md index 53eaf92d..88581702 100644 --- a/zh/12.2.md +++ b/zh/12.2.md @@ -1,8 +1,9 @@ +{% raw %} # 12.2 网站错误处理 我们的Web应用一旦上线之后,那么各种错误出现的概率都有,Web应用日常运行中可能出现多种错误,具体如下所示: - 数据库错误:指与访问数据库服务器或数据相关的错误。例如,以下可能出现的一些数据库错误。 - + - 连接错误:这一类错误可能是数据库服务器网络断开、用户名密码不正确、或者数据库不存在。 - 查询错误:使用的SQL非法导致错误,这样子SQL错误如果程序经过严格的测试应该可以避免。 - 数据错误:数据库中的约束冲突,例如一个唯一字段中插入一条重复主键的值就会报错,但是如果你的应用程序在上线之前经过了严格的测试也是可以避免这类问题。 @@ -27,9 +28,9 @@ 错误处理其实我们已经在十一章第一小节里面有过介绍如何设计错误处理,这里我们再从一个例子详细的讲解一下,如何来处理不同的错误: - 通知用户出现错误: - + 通知用户在访问页面的时候我们可以有两种错误:404.html和error.html,下面分别显示了错误页面的源码: - + @@ -51,7 +52,7 @@ 另一个源码: - + @@ -72,9 +73,9 @@ - + 404的错误处理逻辑,如果是系统的错误也是类似的操作,同时我们看到在: - + func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { sayhelloName(w, r) @@ -90,7 +91,7 @@ ErrorInfo := "文件找不到" //获取当前用户信息 t.Execute(w, ErrorInfo) //执行模板的merger操作 } - + func SystemError(w http.ResponseWriter, r *http.Request) { log.Critical("系统错误") //系统错误触发了Critical,那么不仅会记录日志还会发送邮件 t, _ = t.ParseFiles("tmpl/error.html", nil) //解析模板文件 @@ -109,7 +110,7 @@ username = "" } }() - + username = User[uid] return } @@ -122,3 +123,4 @@ * [目录]() * 上一章: [应用日志](<12.1.md>) * 下一节: [应用部署](<12.3.md>) +{% endraw %} diff --git a/zh/13.3.md b/zh/13.3.md index 68f92de4..97177e55 100644 --- a/zh/13.3.md +++ b/zh/13.3.md @@ -1,3 +1,4 @@ +{% raw %} # 13.3 controller设计 传统的MVC框架大多数是基于Action设计的后缀式映射,然而,现在Web流行REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL,但是为什么不直接设计一个全新的REST风格的 MVC框架呢?本小节就是基于这种思路来讲述如何从头设计一个基于REST风格的MVC框架中的controller,最大限度地简化Web应用的开发,甚至编写一行代码就可以实现“Hello, world”。 @@ -17,7 +18,7 @@ MVC设计模式是目前Web应用开发中最常见的架构模式,通过分 Layout []string TplExt string } - + type ControllerInterface interface { Init(ct *Context, cn string) //初始化上下文和子类名称 Prepare() //开始执行之前的一些处理 @@ -31,7 +32,7 @@ MVC设计模式是目前Web应用开发中最常见的架构模式,通过分 Finish() //执行完成之后的处理 Render() error //执行完method对应的方法之后渲染页面 } - + 那么前面介绍的路由add函数的时候是定义了ControllerInterface类型,因此,只要我们实现这个接口就可以,所以我们的基类Controller实现如下的方法: func (c *Controller) Init(ct *Context, cn string) { @@ -42,43 +43,43 @@ MVC设计模式是目前Web应用开发中最常见的架构模式,通过分 c.Ct = ct c.TplExt = "tpl" } - + func (c *Controller) Prepare() { - + } - + func (c *Controller) Finish() { - + } - + func (c *Controller) Get() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Post() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Delete() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Put() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Head() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Patch() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Options() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } - + func (c *Controller) Render() error { if len(c.Layout) > 0 { var filenames []string @@ -108,10 +109,10 @@ MVC设计模式是目前Web应用开发中最常见的架构模式,通过分 } return nil } - + func (c *Controller) Redirect(url string, code int) { c.Ct.Redirect(code, url) - } + } 上面的controller基类已经实现了接口定义的函数,通过路由根据url执行相应的controller的原则,会依次执行如下: @@ -125,21 +126,21 @@ MVC设计模式是目前Web应用开发中最常见的架构模式,通过分 上面beego框架中完成了controller基类的设计,那么我们在我们的应用中可以这样来设计我们的方法: package controllers - + import ( "github.com/astaxie/beego" ) - + type MainController struct { beego.Controller } - + func (this *MainController) Get() { this.Data["Username"] = "astaxie" this.Data["Email"] = "astaxie@gmail.com" this.TplNames = "index.tpl" } - + 上面的方式我们实现了子类MainController,实现了Get方法,那么如果用户通过其他的方式(POST/HEAD等)来访问该资源都将返回403,而如果是Get来访问,因为我们设置了AutoRender=true,那么在执行完Get方法之后会自动执行Render函数,就会显示如下界面: ![](images/13.4.beego.png?raw=true) @@ -161,3 +162,4 @@ index.tpl的代码如下所示,我们可以看到数据的设置和显示都 * [目录]() * 上一章: [自定义路由器设计](<13.2.md>) * 下一节: [日志和配置设计](<13.4.md>) +{% endraw %} diff --git a/zh/13.5.md b/zh/13.5.md index 803041ce..9c524047 100644 --- a/zh/13.5.md +++ b/zh/13.5.md @@ -1,3 +1,4 @@ +{% raw %} # 13.5 实现博客的增删改 前面介绍了beego框架实现的整体构思以及部分实现的伪代码,这小节介绍通过beego建立一个博客系统,包括博客浏览、添加、修改、删除等操作。 @@ -53,19 +54,19 @@ IndexController: type IndexController struct { beego.Controller } - + func (this *IndexController) Get() { this.Data["blogs"] = models.GetAll() this.Layout = "layout.tpl" this.TplNames = "index.tpl" } - + ViewController: type ViewController struct { beego.Controller } - + func (this *ViewController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) this.Data["Post"] = models.GetBlog(id) @@ -78,12 +79,12 @@ NewController type NewController struct { beego.Controller } - + func (this *NewController) Get() { this.Layout = "layout.tpl" this.TplNames = "new.tpl" } - + func (this *NewController) Post() { inputs := this.Input() var blog models.Blog @@ -99,14 +100,14 @@ EditController type EditController struct { beego.Controller } - + func (this *EditController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) this.Data["Post"] = models.GetBlog(id) this.Layout = "layout.tpl" this.TplNames = "edit.tpl" } - + func (this *EditController) Post() { inputs := this.Input() var blog models.Blog @@ -117,39 +118,39 @@ EditController models.SaveBlog(blog) this.Ctx.Redirect(302, "/") } - + DeleteController type DeleteController struct { beego.Controller } - + func (this *DeleteController) Get() { id, _ := strconv.Atoi(this.Ctx.Input.Params[":id"]) blog := models.GetBlog(id) this.Data["Post"] = blog models.DelBlog(blog) this.Ctx.Redirect(302, "/") - } + } ## model层 package models - + import ( "database/sql" "github.com/astaxie/beedb" _ "github.com/ziutek/mymysql/godrv" "time" ) - + type Blog struct { Id int `PK` Title string Content string Created time.Time } - + func GetLink() beedb.Model { db, err := sql.Open("mymysql", "blog/astaxie/123456") if err != nil { @@ -158,25 +159,25 @@ DeleteController orm := beedb.New(db) return orm } - + func GetAll() (blogs []Blog) { db := GetLink() db.FindAll(&blogs) return } - + func GetBlog(id int) (blog Blog) { db := GetLink() db.Where("id=?", id).Find(&blog) return } - + func SaveBlog(blog Blog) (bg Blog) { db := GetLink() db.Save(&blog) return bg } - + func DelBlog(blog Blog) { db := GetLink() db.Delete(&blog) @@ -199,17 +200,17 @@ layout.tpl - + - + {{.LayoutContent}} - + - + index.tpl

    Blog posts

    @@ -217,7 +218,7 @@ index.tpl
      {{range .blogs}}
    • - {{.Title}} + {{.Title}} from {{.Created}} Edit Delete @@ -229,7 +230,7 @@ view.tpl

      {{.Post.Title}}

      {{.Post.Created}}
      - + {{.Post.Content}} new.tpl @@ -242,7 +243,7 @@ new.tpl edit.tpl - +

      Edit {{.Post.Title}}

      New Blog Post

      @@ -257,3 +258,4 @@ edit.tpl * [目录]() * 上一章: [日志和配置设计](<13.4.md>) * 下一节: [小结](<13.6.md>) +{% endraw %} diff --git a/zh/14.3.md b/zh/14.3.md index c6c20ad2..8376c967 100644 --- a/zh/14.3.md +++ b/zh/14.3.md @@ -1,3 +1,4 @@ +{% raw %} # 14.3 表单及验证支持 在Web开发中对于这样的一个流程可能很眼熟: @@ -28,7 +29,7 @@ Email string `form:text,valid:required|valid_email` Introduce string `form:textarea` } - + 定义好struct之后接下来在controller中这样操作 func (this *AddController) Get() { @@ -36,26 +37,26 @@ this.Layout = "admin/layout.html" this.TplNames = "admin/add.tpl" } - + 在模板中这样显示表单

      New Blog Post

      {{.form.render()}} - + 上面我们定义好了整个的第一步,从struct到显示表单的过程,接下来就是用户填写信息,服务器端接收数据然后验证,最后插入数据库。 func (this *AddController) Post() { var user User form := this.GetInput(&user) if !form.Validates() { - return + return } models.UserInsert(&user) this.Ctx.Redirect(302, "/admin/index") } - + ## 表单类型 以下列表列出来了对应的form元素信息:
    @@ -121,7 +122,7 @@
    - + ## 表单验证 以下列表将列出可被使用的原生规则 @@ -278,4 +279,5 @@ ## links * [目录]() * 上一节: [Session支持](<14.2.md>) - * 下一节: [用户认证](<14.4.md>) \ No newline at end of file + * 下一节: [用户认证](<14.4.md>) +{% endraw %} diff --git a/zh/14.5.md b/zh/14.5.md index 422904a0..5ee02383 100644 --- a/zh/14.5.md +++ b/zh/14.5.md @@ -1,3 +1,4 @@ +{% raw %} # 14.5 多语言支持 我们在第十章介绍过国际化和本地化,开发了一个go-i18n库,这小节我们将把该库集成到beego框架里面来,使得我们的框架支持国际化和本地化。 @@ -21,7 +22,7 @@ beego中设置全局变量如下: beegoTplFuncMap["Trans"] = i18n.I18nT beegoTplFuncMap["TransDate"] = i18n.I18nTimeDate beegoTplFuncMap["TransMoney"] = i18n.I18nMoney - + func I18nT(args ...interface{}) string { ok := false var s string @@ -33,7 +34,7 @@ beego中设置全局变量如下: } return beego.Translation.Translate(s) } - + func I18nTimeDate(args ...interface{}) string { ok := false var s string @@ -44,8 +45,8 @@ beego中设置全局变量如下: s = fmt.Sprint(args...) } return beego.Translation.Time(s) - } - + } + func I18nMoney(args ...interface{}) string { ok := false var s string @@ -60,7 +61,7 @@ beego中设置全局变量如下: ## 多语言开发使用 1. 设置语言以及语言包所在位置,然后初始化i18n对象: - + beego.Lang = "zh" beego.LangPath = "views/lang" beego.InitLang() @@ -68,18 +69,18 @@ beego中设置全局变量如下: 2. 设计多语言包 上面讲了如何初始化多语言包,现在设计多语言包,多语言包是json文件,如第十章介绍的一样,我们需要把设计的文件放在LangPath下面,例如zh.json或者en.json - + # zh.json - + { "zh": { "submit": "提交", "create": "创建" } } - + #en.json - + { "en": { "submit": "Submit", @@ -90,24 +91,25 @@ beego中设置全局变量如下: 3. 使用语言包 我们可以在controller中调用翻译获取响应的翻译语言,如下所示: - + func (this *MainController) Get() { this.Data["create"] = beego.Translation.Translate("create") this.TplNames = "index.tpl" } - + 我们也可以在模板中直接调用响应的翻译函数: - + //直接文本翻译 {{.create | Trans}} - + //时间翻译 - {{.time | TransDate}} - + {{.time | TransDate}} + //货币翻译 - {{.money | TransMoney}} - + {{.money | TransMoney}} + ## links * [目录]() * 上一节: [用户认证](<14.4.md>) - * 下一节: [pprof支持](<14.6.md>) \ No newline at end of file + * 下一节: [pprof支持](<14.6.md>) +{% endraw %} From 61b5bc35e79b07de172f54f12b4a848c7bf41ca4 Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 17:26:46 +0100 Subject: [PATCH 10/32] Hide raw/endraw tags for a regular markdown --- ja/04.3.md | 5 ++--- ja/04.5.md | 4 ++-- ja/06.4.md | 4 ++-- ja/07.1.md | 4 ++-- ja/07.4.md | 4 ++-- ja/09.1.md | 4 ++-- ja/10.2.md | 4 ++-- ja/10.3.md | 4 ++-- ja/12.2.md | 4 ++-- ja/13.3.md | 4 ++-- ja/13.5.md | 4 ++-- ja/14.3.md | 4 ++-- ja/14.5.md | 4 ++-- zh/09.1.md | 4 ++-- zh/10.2.md | 4 ++-- zh/10.3.md | 4 ++-- zh/12.2.md | 4 ++-- zh/13.3.md | 4 ++-- zh/13.5.md | 4 ++-- zh/14.3.md | 4 ++-- zh/14.5.md | 4 ++-- 21 files changed, 42 insertions(+), 43 deletions(-) diff --git a/ja/04.3.md b/ja/04.3.md index 78cf119b..bdbf5816 100644 --- a/ja/04.3.md +++ b/ja/04.3.md @@ -1,4 +1,3 @@ -{% raw %} # 4.3 クロスサイトスクリプティングの予防 現在のホームページは大量の動的なコンテンツを含みユーザのエクスペリエンスを高めています。以前に比べてとても複雑になっています。いわゆる動的なコンテンツとはユーザの環境と要求に応じてWebアプリケーションが目的の内容を出力できることを指します。動的なホームページは"クロスサイトスクリプティング"(Cross Site Scripting、セキュリティ専門家が一般的にXSSと省略するもの)と呼ばれる攻撃を受けることがあります。 @@ -27,7 +26,7 @@ Goではどのようにこの効果的な防御を行なっているのでしょ 図4.3 Javascriptフィルターによる出力 Goのhtml/templateパッケージはデフォルトでhtmlタグをフィルターします。しかし時にはこの``を正常な情報として出力したい場合があるかもしれません。そのような場合はどのように処理するべきでしょうか?この場合はtext/templateをご利用ください。下の例をご覧ください: - + import "text/template" ... t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) @@ -67,4 +66,4 @@ Goのhtml/templateパッケージはデフォルトでhtmlタグをフィルタ * [目次]() * 前へ: [入力値の検証](<04.2.md>) * 次へ: [フォームの複数回送信の防止](<04.4.md>) -{% endraw %} + diff --git a/ja/04.5.md b/ja/04.5.md index c02357e6..4e11b87b 100644 --- a/ja/04.5.md +++ b/ja/04.5.md @@ -1,4 +1,4 @@ -{% raw %} + # 4.5 ファイルのアップロード処理 ユーザによるファイルのアップロードを処理したいとします。例えば、現在Instagramのようなホームページを作成しているとします。ユーザが撮影した写真を保存する必要があります。このような要求はどのように実現するのでしょうか? @@ -156,4 +156,4 @@ * [目次]() * 前へ: [フォームの多重送信の防止](<04.4.md>) * 次へ: [まとめ](<04.6.md>) -{% endraw %} + diff --git a/ja/06.4.md b/ja/06.4.md index 5f001b46..4649f8e1 100644 --- a/ja/06.4.md +++ b/ja/06.4.md @@ -1,4 +1,4 @@ -{% raw %} + # 6.4 sessionハイジャックの予防 sessionハイジャックは広範囲に存在する比較的重大な脆弱性です。session技術において、クライアントサイドとサーバサイドはsessionのIDによってセッションを維持します。しかしこのIDは簡単にスニッフィングされ、第三者に利用されてしまいます。これは中間者攻撃の一種です。 @@ -88,4 +88,4 @@ sessionが始まると、生成されたsessionIDの時間を記録する一つ * [目次]() * 前へ: [sessionストレージ](<06.3.md>) * 次へ: [まとめ](<06.5.md>) -{% endraw %} + diff --git a/ja/07.1.md b/ja/07.1.md index 1ca83bfd..a2158879 100644 --- a/ja/07.1.md +++ b/ja/07.1.md @@ -1,4 +1,4 @@ -{% raw %} + # 7.1 XMLの処理 XMLはデータと情報のやりとりするための形式として十分普及しています。Webサービスが日々広範囲で応用されてくるにつれ、現在XMLは日常的な開発作業において重要な役割を演じてきました。この節ではGo言語の標準パッケージにあるXML関連のパッケージをご紹介します。 @@ -220,4 +220,4 @@ XMLをstructに解析する際は以下のルールに従います:  * [目次]() * 前へ: [テキスト処理](<07.0.md>) * 次へ: [Jsonの処理](<07.2.md>) -{% endraw %} + diff --git a/ja/07.4.md b/ja/07.4.md index 9f5f7150..7b1c2eff 100644 --- a/ja/07.4.md +++ b/ja/07.4.md @@ -1,4 +1,4 @@ -{% raw %} + # 7.4 テンプレートの処理 ## テンプレートとは何か おそらくあなたはMVCのデザインパターンについて聞いたことがあると思います。Modelはデータを処理を、Viewは表示結果を、Controllerはユーザのリクエストの制御を行います。Viewレイヤーの処理では、多くの動的な言語ではどれも静的なHTMLの中に動的言語が生成したデータを挿入します。例えばJSPでは`<%=....=%>`を挿入することで、PHPでは``を挿入することで実現します。 @@ -349,4 +349,4 @@ Webアプリケーションを作る時はテンプレートの一部が固定 * [目次]() * 前へ: [正規表現の処理](<07.3.md>) * 次へ: [ファイルの操作](<07.5.md>) -{% endraw %} + diff --git a/ja/09.1.md b/ja/09.1.md index 74c30a45..9d543f8d 100644 --- a/ja/09.1.md +++ b/ja/09.1.md @@ -1,4 +1,4 @@ -{% raw %} + # 9.1 CSRF攻撃の予防 ## CSRFとは何か  @@ -92,4 +92,4 @@ tokenを検証 * [目次]() * 前へ: [セキュリティと暗号化](<09.0.md>) * 次へ: [入力フィルタリングの確保](<09.2.md>) -{% endraw %} + diff --git a/ja/10.2.md b/ja/10.2.md index c761e099..7db10062 100644 --- a/ja/10.2.md +++ b/ja/10.2.md @@ -1,4 +1,4 @@ -{% raw %} + # 10.2 ローカライズリソース 前の節ではどのようにしてLocaleを設定するかご紹介しました。Localeを設定したあとはどのようにしてLocaleに対応する情報を保存するかという問題を解決する必要があります。ここでの情報とは以下の内容を含みます:テキスト情報、時間と日時、通貨の値、画像、ファイルや動画といったリソース等です。ここではこれらの情報に対してご紹介していきたいと思います。Go言語ではこれらのフォーマットの情報をJSONに保存します。その後それぞれ適した方法によって表示します。(以下では日本語と英語の2つの言語を対比して例を挙げます。保存の形式はそれぞれen.jsonとja-JP.jsonです。) ## ローカライズテキスト情報 @@ -133,4 +133,4 @@ Localeの違いによってビューを表示させる場合もあるかもし * [目次]() * 前へ: [デフォルトロケールの設定](<10.1.md>) * 次へ: [国際化サイト](<10.3.md>) -{% endraw %} + diff --git a/ja/10.3.md b/ja/10.3.md index dfa7eaa1..ed517a3c 100644 --- a/ja/10.3.md +++ b/ja/10.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 10.3 国際化サイト 前の節でどのようにしてローカライズリソースを処理するかご紹介しました。Localeに対応した設定ファイルです。ではもし複数のローカライズリソースを処理する場合は?いくつかの我々が通常使用する例は:簡単なテキスト翻訳、時間や日時、数字といったものはどのように処理するのでしょうか?この節では一つ一つこれらの問題を解決していきます。 ## 複数のロケールパッケージの管理 @@ -179,4 +179,4 @@ * [目次]() * 前へ: [ローカライズリソース](<10.2.md>) * 次へ: [まとめ](<10.4.md>) -{% endraw %} + diff --git a/ja/12.2.md b/ja/12.2.md index f186ac0f..c6201707 100644 --- a/ja/12.2.md +++ b/ja/12.2.md @@ -1,4 +1,4 @@ -{% raw %} + # 12.2 サイトエラー処理 我々のWebアプリケーションが一旦実運用されると、さまざまなエラーが発生する可能性があります。Webアプリケーションの日常の実行ではいくつものエラーが発生する可能性があります。具体的には以下のとおり: @@ -123,4 +123,4 @@ * [目次]() * 前へ: [アプリケーションログ](<12.1.md>) * 次へ: [アプリケーションのデプロイ](<12.3.md>) -{% endraw %} + diff --git a/ja/13.3.md b/ja/13.3.md index 5526c9a8..f772e3c9 100644 --- a/ja/13.3.md +++ b/ja/13.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 13.3 controller設計 伝統的なMVCフレームワークにおいて、多くの場合Action設計のサフィックス反映にもとづいています、しかしながら、現在webではREST風のフレームワークが流行しています。なるべくFilterかrewriteを使用してURLのリライトを行い、REST風のURLを実現しています。しかしなぜ直接新しくREST風のMVCフレームワークを設計しないのでしょうか?本章ではこういった考え方に基いてどのようにREST風のMVCフレームワークにフルスクラッチでcontroller、最大限に簡素化されたWebアプリケーションの開発、ひいては一行で可能な"Hello, world"の実装についてご説明します。 @@ -162,4 +162,4 @@ index.tplのコードは以下のようになります。データの設定と * [目次]() * 前へ: [カスタム定義のルータの設計](<13.2.md>) * 次へ: [ログとコンフィグ設計](<13.4.md>) -{% endraw %} + diff --git a/ja/13.5.md b/ja/13.5.md index b18c68d7..332ef9ec 100644 --- a/ja/13.5.md +++ b/ja/13.5.md @@ -1,4 +1,4 @@ -{% raw %} + # 13.5 ブログの追加/削除/修正の実装 前ではbeegoフレームワークの全体的な構造思想の実装とニセコードの一部の実装についてご紹介しました。この節ではbeegoを通してブログシステムを設計しましょう。これにはブログの閲覧、追加、修正、削除といった操作が含まれます。 @@ -257,4 +257,4 @@ edit.tpl * [目次]() * 前へ: [ログとコンフィグ設計](<13.4.md>) * 次へ: [まとめ](<13.6.md>) -{% endraw %} + diff --git a/ja/14.3.md b/ja/14.3.md index 12408378..a83b568e 100644 --- a/ja/14.3.md +++ b/ja/14.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 14.3 フォームおよび検証のサポート Web開発ではこのようなプロセスをよく見かけます: @@ -280,4 +280,4 @@ structを定義したらcontrollerにおいてこのように操作します * [目次]() * 前へ: [Sessionのサポート](<14.2.md>) * 次へ: [ユーザの認証](<14.4.md>) -{% endraw %} + diff --git a/ja/14.5.md b/ja/14.5.md index a3e3cde0..a2ee37f4 100644 --- a/ja/14.5.md +++ b/ja/14.5.md @@ -1,4 +1,4 @@ -{% raw %} + # 14.5 多言語サポート 第10章において国際化とローカライゼーションおよびgo-i18nライブラリの開発についてご紹介しました。この節ではこのライブラリをbeegoフレームワークの中にもってくることで、我々のフレームワークにおいて国際化とローカライゼーションをサポートさせます。 @@ -112,4 +112,4 @@ beegoにおいて以下のようにグローバル変数を設定します: * [目次]() * 前へ: [ユーザ認証](<14.4.md>) * 次へ: [pprofのサポート](<14.6.md>) -{% endraw %} + diff --git a/zh/09.1.md b/zh/09.1.md index e873bd95..baaed84f 100644 --- a/zh/09.1.md +++ b/zh/09.1.md @@ -1,7 +1,7 @@ -{% raw %} # 9.1 预防CSRF攻击 ## 什么是CSRF + CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。 那么CSRF到底能够干嘛呢?你可以这样简单的理解:攻击者可以盗用你的登陆信息,以你的身份模拟发送各种请求。攻击者只要借助少许的社会工程学的诡计,例如通过QQ等聊天软件发送的链接(有些还伪装成短域名,用户无法分辨),攻击者就能迫使Web应用的用户去执行攻击者预设的操作。例如,当用户登录网络银行去查看其存款余额,在他没有退出时,就点击了一个QQ好友发来的链接,那么该用户银行帐户中的资金就有可能被转移到攻击者指定的帐户中。 @@ -9,6 +9,7 @@ CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也 所以遇到CSRF攻击时,将对终端用户的数据和操作指令构成严重的威胁;当受攻击的终端用户具有管理员帐户的时候,CSRF攻击将危及整个Web应用程序。 ## CSRF的原理 + 下图简单阐述了CSRF攻击的思想 ![](images/9.1.csrf.png?raw=true) @@ -92,4 +93,3 @@ CSRF的防御可以从服务端和客户端两方面着手,防御效果是从 * [目录]() * 上一节: [安全与加密](<09.0.md>) * 下一节: [确保输入过滤](<09.2.md>) -{% endraw %} diff --git a/zh/10.2.md b/zh/10.2.md index b507e8f7..e3ed7a19 100644 --- a/zh/10.2.md +++ b/zh/10.2.md @@ -1,4 +1,4 @@ -{% raw %} + # 10.2 本地化资源 前面小节我们介绍了如何设置Locale,设置好Locale之后我们需要解决的问题就是如何存储相应的Locale对应的信息呢?这里面的信息包括:文本信息、时间和日期、货币值、图片、包含文件以及视图等资源。那么接下来我们将对这些信息一一进行介绍,Go语言中我们把这些格式信息存储在JSON中,然后通过合适的方式展现出来。(接下来以中文和英文两种语言对比举例,存储格式文件en.json和zh-CN.json) ## 本地化文本消息 @@ -133,4 +133,4 @@ $GOROOT/lib/time包中的timeinfo.zip含有locale对应的时区的定义,为 * [目录]() * 上一节: [设置默认地区](<10.1.md>) * 下一节: [国际化站点](<10.3.md>) -{% endraw %} + diff --git a/zh/10.3.md b/zh/10.3.md index 00659ed9..2f702a65 100644 --- a/zh/10.3.md +++ b/zh/10.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 10.3 国际化站点 前面小节介绍了如何处理本地化资源,即Locale一个相应的配置文件,那么如果处理多个的本地化资源呢?而对于一些我们经常用到的例如:简单的文本翻译、时间日期、数字等如果处理呢?本小节将一一解决这些问题。 ## 管理多个本地包 @@ -179,4 +179,4 @@ * [目录]() * 上一节: [本地化资源](<10.2.md>) * 下一节: [小结](<10.4.md>) -{% endraw %} + diff --git a/zh/12.2.md b/zh/12.2.md index 88581702..67ad1965 100644 --- a/zh/12.2.md +++ b/zh/12.2.md @@ -1,4 +1,4 @@ -{% raw %} + # 12.2 网站错误处理 我们的Web应用一旦上线之后,那么各种错误出现的概率都有,Web应用日常运行中可能出现多种错误,具体如下所示: @@ -123,4 +123,4 @@ * [目录]() * 上一章: [应用日志](<12.1.md>) * 下一节: [应用部署](<12.3.md>) -{% endraw %} + diff --git a/zh/13.3.md b/zh/13.3.md index 97177e55..8a8e7aed 100644 --- a/zh/13.3.md +++ b/zh/13.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 13.3 controller设计 传统的MVC框架大多数是基于Action设计的后缀式映射,然而,现在Web流行REST风格的架构。尽管使用Filter或者rewrite能够通过URL重写实现REST风格的URL,但是为什么不直接设计一个全新的REST风格的 MVC框架呢?本小节就是基于这种思路来讲述如何从头设计一个基于REST风格的MVC框架中的controller,最大限度地简化Web应用的开发,甚至编写一行代码就可以实现“Hello, world”。 @@ -162,4 +162,4 @@ index.tpl的代码如下所示,我们可以看到数据的设置和显示都 * [目录]() * 上一章: [自定义路由器设计](<13.2.md>) * 下一节: [日志和配置设计](<13.4.md>) -{% endraw %} + diff --git a/zh/13.5.md b/zh/13.5.md index 9c524047..83888f39 100644 --- a/zh/13.5.md +++ b/zh/13.5.md @@ -1,4 +1,4 @@ -{% raw %} + # 13.5 实现博客的增删改 前面介绍了beego框架实现的整体构思以及部分实现的伪代码,这小节介绍通过beego建立一个博客系统,包括博客浏览、添加、修改、删除等操作。 @@ -258,4 +258,4 @@ edit.tpl * [目录]() * 上一章: [日志和配置设计](<13.4.md>) * 下一节: [小结](<13.6.md>) -{% endraw %} + diff --git a/zh/14.3.md b/zh/14.3.md index 8376c967..bf9bf2e1 100644 --- a/zh/14.3.md +++ b/zh/14.3.md @@ -1,4 +1,4 @@ -{% raw %} + # 14.3 表单及验证支持 在Web开发中对于这样的一个流程可能很眼熟: @@ -280,4 +280,4 @@ * [目录]() * 上一节: [Session支持](<14.2.md>) * 下一节: [用户认证](<14.4.md>) -{% endraw %} + diff --git a/zh/14.5.md b/zh/14.5.md index 5ee02383..e37cfe8d 100644 --- a/zh/14.5.md +++ b/zh/14.5.md @@ -1,4 +1,4 @@ -{% raw %} + # 14.5 多语言支持 我们在第十章介绍过国际化和本地化,开发了一个go-i18n库,这小节我们将把该库集成到beego框架里面来,使得我们的框架支持国际化和本地化。 @@ -112,4 +112,4 @@ beego中设置全局变量如下: * [目录]() * 上一节: [用户认证](<14.4.md>) * 下一节: [pprof支持](<14.6.md>) -{% endraw %} + From 8a802cf8c3749fd46d0fc60abe6ace11384a03fe Mon Sep 17 00:00:00 2001 From: Denis Koltsov Date: Sat, 19 Nov 2016 18:15:54 +0100 Subject: [PATCH 11/32] Fix failing build for a German version because of template tags --- de/02.2.md | 58 +++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/de/02.2.md b/de/02.2.md index 198f79b2..4a640fc4 100644 --- a/de/02.2.md +++ b/de/02.2.md @@ -15,12 +15,12 @@ Definiere mehrere Variablen. // Definiere drei Variablen vom Typ "type" var vname1, vname2, vname3 type - + Definiere eine Variable mit einem Startwert. // Definiere eine Variable mit dem Namen “variableName” vom Typ "type" und dem Wert "value" var variableName type = value - + Definiere mehrere Variablen mit einem Startwert. /* @@ -28,7 +28,7 @@ Definiere mehrere Variablen mit einem Startwert. vname1 ist gleich v1, vname2 ist gleich v2, vname3 ist gleich v3 */ var vname1, vname2, vname3 type = v1, v2, v3 - + Findest Du es nicht auch ein wenig mühsehlig, Variablen auf diesem Weg zu definieren? Keine Sorge, denn das Team hinter Go hat auch so gedacht. Daher kannst Du Variablen Startwerte geben, ohne explizit den Datentyp zu definieren. Der Code würde dann so aussehen: /* @@ -36,7 +36,7 @@ Findest Du es nicht auch ein wenig mühsehlig, Variablen auf diesem Weg zu defin vname1 ist gleich v1, vname2 ist gleich v2, vname3 ist gleich v3 */ var vname1, vname2, vname3 = v1, v2, v3 - + Schön, ich weiß das dies immer noch nicht einfach genug für Dich ist. Mal schauen, wie wir das lösen können. /* @@ -44,7 +44,7 @@ Schön, ich weiß das dies immer noch nicht einfach genug für Dich ist. Mal sch vname1 ist gleich v1,vname2 ist gleich v2,vname3 ist gleich v3 */ vname1, vname2, vname3 := v1, v2, v3 - + So sieht es schon viel besser aus. Nutze `:=`, um `var` und `type` zu ersetzen. Es handelt sich hierbei um eine Kurzschreibweise. Aber warte, es gibt einen kleinen Haken: diese Form der Definition kann nur innerhalb von Fuktionen genutzt werden. Der Compiler wird sonst eine Fehlermeldung ausgeben, wenn Du es trotzdem außerhalb der `{}` einer Funktion versuchst. Daher nutzen wir meist das Schlüsselwort `var` um globale Variablen zu definieren oder die Funktion `var()`. @@ -59,7 +59,7 @@ Wenn Du Variablen in Deinem Programm definierst, aber keine Verwendung finden, w func main() { var i int } - + ## Konstanten Konstanten sind Werte, die während der Kompilierung festgelegt werden und während der Laufzeit nicht veränderbar sind. In Go kannst Du Konstanten als Wert Nummern, Booleans oder Strings geben. @@ -67,7 +67,7 @@ Konstanten sind Werte, die während der Kompilierung festgelegt werden und währ Definiere eine Konstante wie folgt. const constantName = value - // Du kannst auch den Datentyp hinzufügen, wenn nötig + // Du kannst auch den Datentyp hinzufügen, wenn nötig const Pi float32 = 3.1415926 Mehr Beispiele. @@ -76,7 +76,7 @@ Mehr Beispiele. const i = 10000 const MaxThread = 10 const prefix = "astaxie_" - + ## Grundlegende Datentypen ### Boolean @@ -91,7 +91,7 @@ In Go nutzen wir `bool`, um Booleans (Wahrheitswerte) auszudrücken, die entwede valid := false // Kurzschreibweise einer Definition available = true // Eine Variable deklarieren } - + ### Numerische Datentypen Der Datentyp Integer (ganze Zahlen) kann sowohl den positiven, als auch den negativen Zahlenraum umfassen, was durch ein Vorzeichen kenntlich gemacht wird. Go besitzt `int` und `uint`, welche den selben Wertebereich haben. Dessen Größe hängt aber vom Betriebssystem ab. Es werden 32-Bit unter 32-Bit Betriebssystemen verwendet und 64-Bit unter 64-Bit Betriebssystemen. Go umfasst außerdem Datentypen mit einer spezifischen Länge: `rune`, `int8`, `int16`, `int32`, `int64`, `byte`, `uint8`, `uint16`, `uint32` und `uint64`. Bedenke, dass `rune` ein Alias für `int32` ist und `byte` dem `uint8` gleicht. @@ -114,7 +114,7 @@ War das schon alles? Nein! Go unterstützt auch komplexe Zahlen. `complex128` (b var c complex64 = 5+5i // Ausgabe: (5+5i) fmt.Printf("Der Wert ist: %v", c) - + ### Strings Wir sprachen vorhin darüber, das Go eine native UTF-8 Unterstützung mit sich bringt. Strings (Zeichenketten) werden durch Anführungszeichen `""` gekennzeichet, oder durch Backticks (rückwärts geneigtes Hochkomma) ``` `` ```. @@ -140,7 +140,7 @@ Aber was ist, wenn ich wirklich nur ein Zeichen in einem String ändern möchte? c[0] = 'c' s2 := string(c) // Wandle den Wert in eine String zurück fmt.Printf("%s\n", s2) - + Nutze den `+` Operator, um zwei Strings zu verknüpfen. @@ -148,20 +148,20 @@ Nutze den `+` Operator, um zwei Strings zu verknüpfen. m := " Welt" a := s + m fmt.Printf("%s\n", a) - + oder auch s := "Hallo" s = "c" + s[1:] // Du kannst die Werte mit Hilfe des Index nicht verändern, aber sie abfragen fmt.Printf("%s\n", s) - + Was ist, wenn ein String über mehrere Zeilen verlaufen soll? m := `Hallo Welt` - + `\`` wird die Zeichen in einem String escapen (d.h. mit `\` dessen Ausführung verhindern). ### Fehlermeldungen @@ -172,7 +172,7 @@ Go besitzt mit `error` einen eigenen Datentyp, um mit Fehlermeldungen umzugehen. if err != nil { fmt.Print(err) } - + ### Grundeliegende Datenstrukturen Die folgende Grafik enstammt dem Artikel [Datenstrukturen in Go](http://research.swtch.com/godata) (auf englisch) aus [Russ Coxs Blog](http://research.swtch.com/). Wie Du sehen kannst, nutzt Go Abschnitte des Arbeitsspeichers, um Daten zu speichern. @@ -199,7 +199,7 @@ Wenn Du mehrere Konstanten und Variablen deklarieren oder Pakete importieren mö var i int var pi float32 var prefix string - + Gruppierter Ansatz. import( @@ -233,8 +233,8 @@ Go besitzt das Schlüselwort `iota`, um eine Aufzählung zu starten. Der Startwe ) const v = iota // Sobald iota erneut auf `const` trifft, wird erneut mit `0` gestartet, also gilt v = 0. - - const ( + + const ( e, f, g = iota, iota, iota // e, f und g haben den selben Wert 0, da sie in der selben Zeile stehen. ) @@ -261,7 +261,7 @@ wobei in `[n]Datentyp` das `n` die Länge des Arrays angibt. `Datentyp` ist selb fmt.Printf("Das erste Element ist %d\n", arr[0]) // Beim Auslesen des Wertes wird 42 zurückgegeben fmt.Printf("Das letzte Element ist %d\n", arr[9]) // Es gibt den Standardwert des 10. Elements zurück, was in diesem Fall 0 ist. -Da die Länge ein Teil des Array-Typs ist, sind `[3]int` und `[4]int` verschieden, sodass wir die Länge eines Arrays nicht ändern können. Nutzt Du Arrays als Argument in einer Funktion, dann wird eine Kopie des Arrays übergeben, statt einem Zeiger (bzw. ein Verweis) auf das Original. Möchtest Du stattdessen den Zeiger übergeben, dann musst Du einen `slice` verwenden. Darauf gehen wir aber später nochmals ein. +Da die Länge ein Teil des Array-Typs ist, sind `[3]int` und `[4]int` verschieden, sodass wir die Länge eines Arrays nicht ändern können. Nutzt Du Arrays als Argument in einer Funktion, dann wird eine Kopie des Arrays übergeben, statt einem Zeiger (bzw. ein Verweis) auf das Original. Möchtest Du stattdessen den Zeiger übergeben, dann musst Du einen `slice` verwenden. Darauf gehen wir aber später nochmals ein. Es ist möglich, `:=` zu nutzen, um ein Array zu deklarieren. @@ -273,10 +273,10 @@ Vielleicht möchtest Du auch Arrays als Element in einem Array nutzen. Schauen w // Deklariere ein zweidimensionales Array mit zwei Elementen, welche jeweils vier Elemente besitzen. doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} - + + // Die Dekleration kann auch ein wenig kompakter geschrieben werden. - easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} - +{% raw %} easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} {% endraw %} Arrays sind grundlegende Datenstrukturen in Go. @@ -308,12 +308,12 @@ Nun deklarieren wir ein `slice` und vergeben Startwerte. // 'a' verweist auf die Elemente zwischen Index 3 und 5 im Array ar. a = ar[2:5] // 'a' besitzt nun die Elemente ar[2],ar[3] und ar[4] - + // 'b' ist ein weiterer Ausschnitt (Slice) vom Array ar b = ar[3:5] // 'b' besitzt nun die Elemente ar[3] und ar[4] -Beachte die Unterscheide bei der Deklaration von `slice` und `array`. Wir nutzen `[…]`, um Go die Länge automatisch herausfinden zu lassen, aber nutzen `[]` lediglich zur Deklaration von Slices. +Beachte die Unterscheide bei der Deklaration von `slice` und `array`. Wir nutzen `[…]`, um Go die Länge automatisch herausfinden zu lassen, aber nutzen `[]` lediglich zur Deklaration von Slices. Ihre zugrundeliegenden Datentypen. @@ -325,7 +325,7 @@ Slices haben bestimmte Anwendungsgebiete. - Ein `slice` beginnt mit dem Index 0, `ar[:n]` gleicht `ar[0:n]`. - Der zweite Index gibt die Länge vom Slice an, wenn er ausgelassen wird. `ar[n:]` gleicht `ar[n:len(ar)]`. -- Du kannst auch `ar[:]` nutzen, um einen gesamtes Array zu kopieren, wie in den ersten beiden Punkten erklärt. +- Du kannst auch `ar[:]` nutzen, um einen gesamtes Array zu kopieren, wie in den ersten beiden Punkten erklärt. Mehr Beispiele zu `slice` @@ -383,7 +383,7 @@ Schauen wir uns ein wenig Code an. Die 'set'- und 'get'-Werte in `map` sind der // Ein alternativer Weg zum Deklarieren nummern := make(map[string]int) nummern["eins"] = 1 // Weise ein Wert durch einen Schlüssel zu - nummern["zehn"] = 10 + nummern["zehn"] = 10 nummern["drei"] = 3 fmt.Println("Die dritte Nummer lautet: ", nummern["drei"]) // Lese den Wert aus @@ -398,7 +398,7 @@ Einige Anmerkungen zur Nutzung von maps. Du kannst das Schema `Schlüssel:Wert` nutzen, um eine `map` mit Startwerten zu erstellen. `map` hat auch eingebaute Funktionen, um die Existenz eines `key` zu überprüfen. -Benutze `delete`, um ein Element in `map` zu löschen. +Benutze `delete`, um ein Element in `map` zu löschen. // Erstelle eine map bewertung := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 } @@ -450,9 +450,9 @@ Standardwerte besitzen einen Wert. Dies sind die gebräuchlichsten Anwendungsfä float64 0 // Die Größe beträgt 8 Byte bool false string "" - + ## Links - [Inhaltsverzeichnis](preface.md) - Vorheriger Abschnitt: ["Hallo Go"](02.1.md) -- Nächster Abschnitt: [Kontrollstrukturen und Funktionen](02.3.md) \ No newline at end of file +- Nächster Abschnitt: [Kontrollstrukturen und Funktionen](02.3.md) From 0aa45a759fbba37494e4bbac1df913d98f79974f Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 24 Nov 2016 19:41:33 +0100 Subject: [PATCH 12/32] fix typos --- de/01.1.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/de/01.1.md b/de/01.1.md index 4cd6fb45..f8ff2fbf 100644 --- a/de/01.1.md +++ b/de/01.1.md @@ -2,11 +2,11 @@ ## Drei Wege Go zu installieren -Es gibt viele Wege, um eine Go-Entwicklungsumgebung auf Deinem Computer einzurichten und Du kannst die auswählen, welche Dir gefällt. Die Folgenden sind die drei Häufigsten: +Es gibt viele Wege, um eine Go-Entwicklungsumgebung auf Deinem Computer einzurichten und Du kannst die auswählen, welche Dir gefällt. Die Folgenden sind die drei Häufigsten: - Offizielle Installationspakete. - Das Team um Go stellt praktische Installationspakete für Windows, Linux, Mac und andere Betriebssysteme zur Verfügung. Dies ist wahrscheinlich der einfachste Weg, um zu starten. -- Eingenhändige Kompilierung des Quellcodes. +- Eigenhändige Kompilierung des Quellcodes. - Beliebt untern Entwicklern, die mit UNIX-ähnlichen Systemen vertraut sind. - Nutze Programme von Dritten. - Da Draußen gibt es eine Menge Werkzeuge von Drittanbietern und Paketmanager, um Go zu installieren, wie apt-get in Ubuntu oder homebrew für Mac. @@ -15,9 +15,9 @@ Es gibt viele Wege, um eine Go-Entwicklungsumgebung auf Deinem Computer einzuric Im Fall, dass Du mehr als eine Version von Go auf Deinem Computer installieren möchtest, dann empfehle ich Dir, einen Blick auf [GVM](https://github.com/moovweb/gvm) zu werfen. Es ist die bisher beste Möglichkeit, die ich soweit gesehen habe, um dies zu tun. Andernfalls musst Du diese Aufgabe selbst bewältigen. -## Eingenhändige Kompilierung des Quellcodes +## Eigenhändige Kompilierung des Quellcodes -Da einige Bestandteile von Go in Plan 9 C und AT&T Assembler geschrieben sind, musst Du einen C-Compiler installieren, bevor Du den nächsten Schritt durchführst. +Da einige Bestandteile von Go in Plan 9 C und AT&T Assembler geschrieben sind, musst Du einen C-Compiler installieren, bevor Du den nächsten Schritt durchführst. Auf dem Mac, sofern Du Xcode installiert hast, ist bereits ein entsprechender Compiler vorhanden. From 5b3f6299850b6f267503a7c9e1a89eac10250c43 Mon Sep 17 00:00:00 2001 From: "Kelvin S. do Prado" Date: Sat, 26 Nov 2016 11:00:21 -0200 Subject: [PATCH 13/32] Translation of section 2.2 to Portuguese (PT_BR). --- pt-br/02.2.md | 346 +++++++++++++++++++++++++------------------------- 1 file changed, 174 insertions(+), 172 deletions(-) diff --git a/pt-br/02.2.md b/pt-br/02.2.md index 2e1e8553..a6fd793e 100644 --- a/pt-br/02.2.md +++ b/pt-br/02.2.md @@ -1,57 +1,57 @@ # 2.2 Fundamentos Go -In this section, we are going to teach you how to define constants, variables with elementary types and some skills in Go programming. +Nesta seção vamos aprender como definir constantes, variáveis com tipos elementares e algumas habilidades de programação em Go. -## Define variables +## Definir variáveis -There are many forms of syntax that can be used to define variables in Go. +Existem diversas formas de sintaxe que podem ser utilizadas para definir variáveis em Go. -The keyword `var` is the basic form to define variables, notice that Go puts the variable type `after` the variable name. +A palavra-chave `var` é a forma mais básica de definir variáveis. Observe que a linguagem Go coloca o tipo da variável `depois` do nome da variável. - // define a variable with name “variableName” and type "type" + // define uma variável com o nome “variableName” e o tipo "type" var variableName type -Define multiple variables. +Definir múltiplas variáveis. - // define three variables which types are "type" + // define três variáveis do tipo "type" var vname1, vname2, vname3 type -Define a variable with initial value. +Definir uma variável com um valor inicial. - // define a variable with name “variableName”, type "type" and value "value" + // define uma variável com o nome “variableName”, tipo "type" e valor "value" var variableName type = value -Define multiple variables with initial values. +Definir múltiplas variáveis com valores iniciais. /* - Define three variables with type "type", and initialize their values. - vname1 is v1, vname2 is v2, vname3 is v3 + Define três variáveis de tipo "type" e inicializa seus valores. + vname1 recebe v1, vname2 recebe v2, vname3 recebe v3 */ var vname1, vname2, vname3 type = v1, v2, v3 -Do you think that it's too tedious to define variables use the way above? Don't worry, because the Go team has also found this to be a problem. Therefore if you want to define variables with initial values, we can just omit the variable type, so the code will look like this instead: +Você acha muito tedioso definir variáveis desta maneira? Não se preocupe porque a equipe da Go também achou que isto poderia ser um problema. Portanto, se você deseja definir variáveis com valores iniciais, pode simplesmente omitir o tipo da variável. Sendo assim, o código ficará da seguinte forma: /* - Define three variables without type "type", and initialize their values. - vname1 is v1,vname2 is v2,vname3 is v3 + Define três variáveis sem o tipo "type" e inicializa seus valores. + vname1 recebe v1, vname2 recebe v2, vname3 recebe v3 */ var vname1, vname2, vname3 = v1, v2, v3 -Well, I know this is still not simple enough for you. Let's see how we fix it. +Bem, talvez isto ainda não seja simples o suficiente para você. Vamos ver como podemos melhorar. /* - Define three variables without type "type" and without keyword "var", and initialize their values. - vname1 is v1,vname2 is v2,vname3 is v3 + Define três variáveis sem o tipo "type", sem a palavra-chave "var" e inicializa seus valores. + vname1 recebe v1, vname2 recebe v2, vname3 recebe v3 */ vname1, vname2, vname3 := v1, v2, v3 -Now it looks much better. Use `:=` to replace `var` and `type`, this is called a brief statement. But wait, it has one limitation: this form can only be used inside of functions. You will get compile errors if you try to use it outside of function bodies. Therefore, we usually use `var` to define global variables and we can use this brief statement in `var()`. +Agora parece muito melhor. Use `:=` para substituir `var` e `type`. Isto é chamado de uma "declaração curta" (do inglês: brief statement). Mas espere, isto possui uma limitação: esta forma só pode ser utilizada dentro de funções. Você receberá erros de compilação se tentar utilizar isto fora do corpo de uma função. Portanto, normalmente utilizamos `var` para definir variáveis globais e podemos utilizar esta declaração curta em `var()`. -`_` (blank) is a special variable name. Any value that is given to it will be ignored. For example, we give `35` to `b`, and discard `34`.( ***This example just show you how it works. It looks useless here because we often use this symbol when we get function return values.*** ) +`_` (blank) é um nome especial de variável. Qualquer valor que seja atribuído a isto será ignorado. Por exemplo, vamos atribuir o valor `35` a variável `b` e descartar o valor `34`.( ***Este exemplo apenas mostra como isto funciona. Ele parece inútil aqui porque frequentemente utilizamos este símbolo quando recebemos valores de retorno de uma função. *** ) _, b := 34, 35 -If you don't use variables that you've defined in your program, the compiler will give you compilation errors. Try to compile the following code and see what happens. +Se você não utilizar variáveis que foram definidas no seu programa, o compilador irá gerar erros de compilação. Tente compilar o seguinte código e veja o que acontece. package main @@ -59,43 +59,43 @@ If you don't use variables that you've defined in your program, the compiler wil var i int } -## Constants +## Constantes -So-called constants are the values that are determined during compile time and you cannot change them during runtime. In Go, you can use number, boolean or string as types of constants. +Constantes são os valores que são determinados durante o tempo de compilação e você não pode alterá-los durante a execução. Em Go, você pode utilizar número, booleano ou string como tipos de constantes. -Define constants as follows. +Defina as constantes da seguinte forma. const constantName = value - // you can assign type of constants if it's necessary + // você pode atribuir o tipo da constante se for necessário const Pi float32 = 3.1415926 -More examples. +Mais exemplos. const Pi = 3.1415926 const i = 10000 const MaxThread = 10 const prefix = "astaxie_" -## Elementary types +## Tipos elementares -### Boolean +### Booleano -In Go, we use `bool` to define a variable as boolean type, the value can only be `true` or `false`, and `false` will be the default value. ( ***You cannot convert variables' type between number and boolean!*** ) +Em Go, utilizamos `bool` para definir uma variável do tipo booleano, sendo que o valor só pode ser `true` ou `false`, e o valor padrão será `false`. ( ***Você não pode converter tipos de variáveis' entre número e booleano!*** ) - // sample code - var isActive bool // global variable - var enabled, disabled = true, false // omit type of variables + // código de amostra + var isActive bool // variável global + var enabled, disabled = true, false // omite o tipo das variáveis func test() { - var available bool // local variable - valid := false // brief statement of variable - available = true // assign value to variable + var available bool // variável local + valid := false // declaração curta de variável + available = true // atribui um valor à variável } -### Numerical types +### Tipos numéricos -Integer types include both signed and unsigned integer types. Go has `int` and `uint` at the same time, they have same length, but specific length depends on your operating system. They use 32-bit in 32-bit operating systems, and 64-bit in 64-bit operating systems. Go also has types that have specific length including `rune`, `int8`, `int16`, `int32`, `int64`, `byte`, `uint8`, `uint16`, `uint32`, `uint64`. Note that `rune` is alias of `int32` and `byte` is alias of `uint8`. +Tipos inteiros incluem tipos com sinais e sem sinais. Go possui os tipos `int` e `uint`, os quais possuem o mesmo comprimento, porém, o comprimento específico depende do sistema operacional. Eles utilizam 32 bits em sistemas operacionais 32 bits e 64 bits em sistemas operacionais de 64 bits. Go também têm tipos que possuem comprimentos específicos, incluindo `rune`, `int8`, `int16`, `int32`, `int64`, `byte`, `uint8`, `uint16`, `uint32`, `uint64`. Note que `rune` é um pseudônimo de `int32` e `byte` é um pseudônimo de `uint8`. -One important thing you should know that you cannot assign values between these types, this operation will cause compile errors. +Uma coisa importante que você deve saber é que você não pode atribuir valores entre estes tipos, esta operação irá gerar erros de compilação. var a int8 @@ -103,86 +103,88 @@ One important thing you should know that you cannot assign values between these c := a + b -Although int32 has a longer length than int8, and has the same type as int, you cannot assign values between them. ( ***c will be asserted as type `int` here*** ) +Embora int32 tenha um comprimento maior do que int8, e possui o mesmo tipo int, você não pode atribuir valores entre eles. ( ***neste caso, c será declarado como tipo `int`*** ) -Float types have the `float32` and `float64` types and no type called `float`. The latter one is the default type if using brief statement. +Tipos float possuem os tipos `float32` e `float64` e nenhum tipo chamado `float`. O último é o tipo padrão utilizado em declarações curtas. -That's all? No! Go supports complex numbers as well. `complex128` (with a 64-bit real and 64-bit imaginary part) is the default type, if you need a smaller type, there is one called `complex64` (with a 32-bit real and 32-bit imaginary part). Its form is `RE+IMi`, where `RE` is real part and `IM` is imaginary part, the last `i` is imaginary number. There is a example of complex number. +Isto é tudo? Não! Go também suporta números complexos. `complex128` (com uma parte de 64 bits real e uma parte de 64 bits imaginária) é o tipo padrão, mas se você precisa de um tipo menor, existe um tipo chamado `complex64` (com uma parte de 32 bits real e uma parte de 32 bits imaginária). + +Sua forma é `RE+IMi`, onde `RE` é a parte real e `IM` é a parte imaginária, e o último `i` é o número imaginário. Há um exemplo de número complexo. var c complex64 = 5+5i - //output: (5+5i) + // saída: (5+5i) fmt.Printf("Value is: %v", c) ### String -We just talked about how Go uses the UTF-8 character set. Strings are represented by double quotes `""` or backticks ``` `` ```. +Nós apenas falamos sobre como a linguagem Go utiliza o conjunto de caracteres UTF-8. As strings são representadas por aspas duplas `""` ou crases (backticks) ``` `` ```. - // sample code - var frenchHello string // basic form to define string - var emptyString string = "" // define a string with empty string + // código de amostra + var frenchHello string // forma básica de definir string + var emptyString string = "" // define uma string vazia func test() { - no, yes, maybe := "no", "yes", "maybe" // brief statement + no, yes, maybe := "no", "yes", "maybe" // declaração curta japaneseHello := "Ohaiou" - frenchHello = "Bonjour" // basic form of assign values + frenchHello = "Bonjour" // forma básica de atribuir valores } -It's impossible to change string values by index. You will get errors when you compile following code. +É impossível alterar valores de string pelo índice. Você receberá erros ao compilar o seguinte código. var s string = "hello" s[0] = 'c' -What if I really want to change just one character in a string? Try following code. +E se eu realmente quiser alterar apenas um caractere de uma string? Tente o seguinte código. s := "hello" - c := []byte(s) // convert string to []byte type + c := []byte(s) // converte string para o tipo []byte c[0] = 'c' - s2 := string(c) // convert back to string type + s2 := string(c) // converte novamente para o tipo string fmt.Printf("%s\n", s2) -You use the `+` operator to combine two strings. +Use o operador `+` para combinar duas strings. s := "hello," m := " world" a := s + m fmt.Printf("%s\n", a) -and also. +e também. s := "hello" - s = "c" + s[1:] // you cannot change string values by index, but you can get values instead. + s = "c" + s[1:] // você não pode alterar valores da string pelo índice, mas você pode obter os valores fmt.Printf("%s\n", s) -What if I want to have a multiple-line string? +E se eu quiser ter uma string de múltiplas linhas? m := `hello world` -`` ` will not escape any characters in a string. +`` ` não irá escapar nenhum caractere da string. -### Error types +### Tipos error -Go has one `error` type for purpose of dealing with error messages. There is also a package called `errors` to handle errors. +Go possui um tipo `error` com o propósito de lidar com mensagens de erro. Há também um pacote chamado `errors` para lidar com os erros. err := errors.New("emit macho dwarf: elf header corrupted") if err != nil { fmt.Print(err) } -### Underlying data structure +### Estrutura de dados subjacente -The following picture comes from an article about [Go data structure](http://research.swtch.com/godata) in [Russ Cox Blog](http://research.swtch.com/). As you can see, Go utilizes blocks of memory to store data. +A seguinte imagem vem de um artigo sobre [estruturas de dados em Go](http://research.swtch.com/godata) do [Blog Russ Cox](http://research.swtch.com/). Como você pode ver, Go utiliza blocos de memória para armazenar dados. ![](images/2.2.basic.png?raw=true) -Figure 2.1 Go underlying data structure +Figure 2.1 Estrutura de dados subjacente em Go -## Some skills +## Algumas habilidades -### Define by group +### Definir por grupo -If you want to define multiple constants, variables or import packages, you can use the group form. +Se você deseja definir múltiplas constantes, variáveis ou importar pacotes, você pode utilizar uma forma de grupo. -Basic form. +Forma básica. import "fmt" import "os" @@ -195,7 +197,7 @@ Basic form. var pi float32 var prefix string -Group form. +Forma de grupo. import( "fmt" @@ -214,191 +216,191 @@ Group form. prefix string ) -Unless you assign the value of constant is `iota`, the first value of constant in the group `const()` will be `0`. If following constants don't assign values explicitly, their values will be the same as the last one. If the value of last constant is `iota`, the values of following constants which are not assigned are `iota` also. +A menos que você atribua, o valor da constante é `iota`, o primeiro valor de constante no grupo `const()` será `0`. Se as constantes seguintes não atribuirem valores explicitamente, seus valores serão iguais ao último. Se o valor da última constante é `iota`, os valores das constantes seguintes que não são atribuídas será `iota` também. -### iota enumerate +### Enumeração iota -Go has one keyword called `iota`, this keyword is to make `enum`, it begins with `0`, increased by `1`. +Go possui uma palavra-chave chamada `iota`, esta palavra-chave é utilizada para fazer `enum`, ela começa com `0` e aumenta de 1 em 1. const( x = iota // x == 0 y = iota // y == 1 z = iota // z == 2 - w // If there is no expression after the constants name, it uses the last expression, so it's saying w = iota implicitly. Therefore w == 3, and y and x both can omit "= iota" as well. + w // se não há nenhuma expressão após o nome da constate, ele usa a última expressão, ou seja, está definindo w = iota implicitamente. Portanto, w == 3, e y e x podem omitir "= iota" também. ) - const v = iota // once iota meets keyword `const`, it resets to `0`, so v = 0. + const v = iota // uma vez que iota encontra a palavra-chave `const`, ela é redefinida para `0`, então v = 0. const ( - e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line. + e, f, g = iota, iota, iota // e=0,f=0,g=0 valores de iota são iguais em uma linha. ) -### Some rules +### Algumas regras -The reason that Go is concise because it has some default behaviors. +A razão de Go ser concisa é porque ela possui alguns comportamentos padrão. -- Any variable that begins with a capital letter means it will be exported, private otherwise. -- The same rule applies for functions and constants, no `public` or `private` keyword exists in Go. +- Qualquer variável que começa com uma letra maiúscula significa que ela será exportada, caso contrário será privada. +- A mesma regra se aplica para funções e constantes, sendo que não existem as palavras-chave `public` ou `private` em Go. ## array, slice, map ### array -`array` is an array obviously, we define one as follows. +`array` é um array obviamente, e nós definimos ele da seguinte maneira. var arr [n]type -in `[n]type`, `n` is the length of the array, `type` is the type of its elements. Like other languages, we use `[]` to get or set element values within arrays. +em `[n]type`, `n` é o comprimento do array, enquanto `type` é o tipo dos elementos contidos no array. Assim como em outras linguagens, nós utilizamos `[]` para obter ou definir valores de elementos no array. - var arr [10]int // an array of type [10]int - arr[0] = 42 // array is 0-based - arr[1] = 13 // assign value to element - fmt.Printf("The first element is %d\n", arr[0]) // get element value, it returns 42 - fmt.Printf("The last element is %d\n", arr[9]) //it returns default value of 10th element in this array, which is 0 in this case. + var arr [10]int // um array de tipo [10]int + arr[0] = 42 // array é baseado em 0 + arr[1] = 13 // atribuir um valor ao elemento + fmt.Printf("The first element is %d\n", arr[0]) // obtém o valor do elemento, irá retornar 42 + fmt.Printf("The last element is %d\n", arr[9]) // retorna o valor padrão do elemento da posição 10 do array, que, neste caso, é 0. -Because length is a part of the array type, `[3]int` and `[4]int` are different types, so we cannot change the length of arrays. When you use arrays as arguments, functions get their copies instead of references! If you want to use references, you may want to use `slice`. We'll talk about later. +Como o comprimento faz parte do tipo do array, `[3]int` e `[4]int` são tipos diferentes, portanto, não podemos alterar o comprimento dos arrays. Quando você utiliza arrays como argumentos, as funções obtêm suas copias em vez de referências! Se você deseja utilizar referências, você pode utilizar `slice`. Falaremos sobre isto mais tarde. -It's possible to use `:=` when you define arrays. +É possível utilizar `:=` quando você define arrays. - a := [3]int{1, 2, 3} // define an int array with 3 elements + a := [3]int{1, 2, 3} // define um array de inteiros com 3 elementos - b := [10]int{1, 2, 3} // define a int array with 10 elements, of which the first three are assigned. The rest of them use the default value 0. + b := [10]int{1, 2, 3} // define um array de inteiros com 10 elementos, dos quais os 3 primeiros são atribuídos. O restante deles recebe o valor padrão 0. - c := [...]int{4, 5, 6} // use `…` to replace the length parameter and Go will calculate it for you. + c := [...]int{4, 5, 6} // usa `…` para substituir o parâmetro de comprimento e a Go irá calcular isto para você. -You may want to use arrays as arrays' elements. Let's see how to do this. +Você pode querer utilizar arrays como elementos de arrays'. Vamos ver como fazer isto. - // define a two-dimensional array with 2 elements, and each element has 4 elements. + // define um array bidimensional com 2 elementos, e cada elemento possui 4 elementos doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} - // The declaration can be written more concisely as follows. + // A declaração pode ser escrita de forma mais concisa da seguinte forma. easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} -Array underlying data structure. +Array estrutura de dados subjacente. ![](images/2.2.array.png?raw=true) -Figure 2.2 Multidimensional array mapping relationship +Figure 2.2 Relação de mapeamento de array multidimensional ### slice -In many situations, the array type is not a good choice -for instance when we don't know how long the array will be when we define it. Thus, we need a "dynamic array". This is called `slice` in Go. +Em várias situações, o tipo array não é uma boa escolha -por exemplo quando não sabemos o comprimento que o array terá quando o definimos. Sendo assim, precisamos de um "array dinâmico". Isto é chamado de `slice` em Go. -`slice` is not really a `dynamic array`. It's a reference type. `slice` points to an underlying `array` whose declaration is similar to `array`, but doesn't need length. +`slice` não é realmente um `array dinâmico`. É um tipo de referência. `slice` aponta para um `array` subjacente cuja declaração é semelhante ao `array`, porém não precisa de um comprimento preestabelecido. - // just like defining an array, but this time, we exclude the length. + // definimos um slice assim como definimos um array, mas desta vez, omitimos o comprimento var fslice []int -Then we define a `slice`, and initialize its data. +Então nós definimos um `slice` e inicializamos seus dados. slice := []byte {'a', 'b', 'c', 'd'} -`slice` can redefine existing slices or arrays. `slice` uses `array[i:j]` to slice, where `i` is the start index and `j` is end index, but notice that `array[j]` will not be sliced since the length of the slice is `j-i`. +`slice` pode redefinir slices ou arrays existentes. `slice` usa `array[i:j]` para "cortar", onde `i` é o índice de início e `j` é o índice final, mas observe que o valor de `array[j]` não será incluído no slice, pois o comprimento da fatia é `j-i`. - // define an array with 10 elements whose types are bytes + // define um array com 10 elementos cujos tipos são bytes var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - // define two slices with type []byte + // define dois slices com o tipo []byte var a, b []byte - // 'a' points to elements from 3rd to 5th in array ar. + // 'a' aponta para os elementos da terceira até a quinta posição do array ar a = ar[2:5] - // now 'a' has elements ar[2],ar[3] and ar[4] + // agora 'a' possui os elementos ar[2], ar[3] e ar[4] - // 'b' is another slice of array ar + // 'b' é outro slice do array ar b = ar[3:5] - // now 'b' has elements ar[3] and ar[4] + // agora 'b' possui os elementos ar[3] e ar[4] -Notice the differences between `slice` and `array` when you define them. We use `[…]` to let Go calculate length but use `[]` to define slice only. +Observe as diferenças entre `slice` e `array` quando você define eles. Nós utilizamos `[…]` para deixar a linguagem Go calcular o comprimento, mas utilizamos `[]` para definir um slice. -Their underlying data structure. +Sua estrutura de dados subjacente. ![](images/2.2.slice.png?raw=true) -Figure 2.3 Correspondence between slice and array +Figure 2.3 Relação enter slice e array -slice has some convenient operations. +slice possui algumas operações convenientes. -- `slice` is 0-based, `ar[:n]` equals to `ar[0:n]` -- The second index will be the length of `slice` if omitted, `ar[n:]` equals to `ar[n:len(ar)]`. -- You can use `ar[:]` to slice whole array, reasons are explained in first two statements. +- `slice` é baseado em 0, `ar[:n]` igual a `ar[0:n]` +- Se omitido, o segundo índice será o comprimento do `slice`, `ar[n:]` igual a `ar[n:len(ar)]`. +- Você pode usar `ar[:]` para "cortar" o array inteiro, as razões são explicadas nas duas primeiras declarações. -More examples pertaining to `slice` +Mais exemplos referentes a `slice` - // define an array + // define um array var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - // define two slices + // define dois slices var aSlice, bSlice []byte - // some convenient operations - aSlice = array[:3] // equals to aSlice = array[0:3] aSlice has elements a,b,c - aSlice = array[5:] // equals to aSlice = array[5:10] aSlice has elements f,g,h,i,j - aSlice = array[:] // equals to aSlice = array[0:10] aSlice has all elements + // algumas operações convenientes + aSlice = array[:3] // igual a aSlice = array[0:3] aSlice possui os elementos a,b,c + aSlice = array[5:] // igual a aSlice = array[5:10] aSlice possui os elementos f,g,h,i,j + aSlice = array[:] // igual a aSlice = array[0:10] aSlice possui todos os elementos - // slice from slice - aSlice = array[3:7] // aSlice has elements d,e,f,g,len=4,cap=7 - bSlice = aSlice[1:3] // bSlice contains aSlice[1], aSlice[2], so it has elements e,f - bSlice = aSlice[:3] // bSlice contains aSlice[0], aSlice[1], aSlice[2], so it has d,e,f - bSlice = aSlice[0:5] // slice could be expanded in range of cap, now bSlice contains d,e,f,g,h - bSlice = aSlice[:] // bSlice has same elements as aSlice does, which are d,e,f,g + // slice de um slice + aSlice = array[3:7] // aSlice possui os elementos d,e,f,g,len=4,cap=7 + bSlice = aSlice[1:3] // bSlice contém aSlice[1], aSlice[2], então têm os elementos e,f + bSlice = aSlice[:3] // bSlice contém aSlice[0], aSlice[1], aSlice[2], então têm os elementos d,e,f + bSlice = aSlice[0:5] // slice pode ser expandido no intervalo de cap, agora bSlice contém d,e,f,g,h + bSlice = aSlice[:] // bSlice têm os mesmos elementos do slice aSlice, os quais são d,e,f,g -`slice` is a reference type, so any changes will affect other variables pointing to the same slice or array. For instance, in the case of `aSlice` and `bSlice` above, if you change the value of an element in `aSlice`, `bSlice` will be changed as well. +`slice` é um tipo de referência, portanto, qualquer alteração irá afetar outras variáveis que apontam para o mesmo slice ou array. Por exemplo, no caso dos slices `aSlice` e `bSlice` apresentado acima, se você alterar o valor de um elemento em `aSlice`, `bSlice` também será alterado. -`slice` is like a struct by definition and it contains 3 parts. +`slice` é como uma estrutura por definição, e contém 3 partes. -- A pointer that points to where `slice` starts. -- The length of `slice`. -- Capacity, the length from start index to end index of `slice`. +- Um ponteiro que aponta para onde o `slice` inicia. +- O comprimento do `slice`. +- Capacidade, o comprimento do índice de início para o índice final do `slice`. Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} Slice_a := Array_a[2:5] -The underlying data structure of the code above as follows. +Segue a seguir a estrutura subjacente do código acima. ![](images/2.2.slice2.png?raw=true) -Figure 2.4 Array information of slice +Figure 2.4 Informações do slice de um array -There are some built-in functions for slice. +Existem algumas funções incorporadas no slice. -- `len` gets the length of `slice`. -- `cap` gets the maximum length of `slice` -- `append` appends one or more elements to `slice`, and returns `slice` . -- `copy` copies elements from one slice to the other, and returns the number of elements that were copied. +- `len` obtém o comprimento do `slice`. +- `cap` obtém o comprimento máximo do `slice`. +- `append` acrescenta um ou mais elementos ao `slice`, e retorna um `slice`. +- `copy` copia elementos de um slice para outro e retorna o número de elementos que foram copiados. -Attention: `append` will change the array that `slice` points to, and affect other slices that point to the same array. Also, if there is not enough length for the slice (`(cap-len) == 0`), `append` returns a new array for this slice. When this happens, other slices pointing to the old array will not be affected. +Atenção: `append` irá alterar o array para onde o `slice` aponta e afetará também outros slices que apontam para o mesmo array. Além disto, se não houver comprimento suficiente para o slice (`(cap-len) == 0`), `append` retorna um novo array para o slice. Quando isto acontece, outros slices que estão apontando para o array antigo não serão afetados. ### map -`map` behaves like a dictionary in Python. Use the form `map[keyType]valueType` to define it. +`map` se comporta como um dicionário em Python. Use a forma `map[keyType]valueType` para defini-lo. -Let's see some code. The 'set' and 'get' values in `map` are similar to `slice`, however the index in `slice` can only be of type 'int' while `map` can use much more than that: for example `int`, `string`, or whatever you want. Also, they are all able to use `==` and `!=` to compare values. +Vamos ver um pouco de código. Os valores 'set' e 'get' em `map` são semelhantes ao `slice`, no entanto, o índice no `slice` só pode ser do tipo 'int' enquanto `map` pode usar muitos outros tipos, como por exemplo: `int`, `string`, ou qualquer outro que você quiser. Além disto, eles são capazes de usar `==` e `!=` para comparar valores. - // use string as the key type, int as the value type, and `make` initialize it. + // use string como o tipo chave, int como o tipo valor e `make` para inicializar. var numbers map[string] int - // another way to define map + // outra forma de definir map numbers := make(map[string]int) - numbers["one"] = 1 // assign value by key + numbers["one"] = 1 // atribui valor por chave numbers["ten"] = 10 numbers["three"] = 3 - fmt.Println("The third number is: ", numbers["three"]) // get values - // It prints: The third number is: 3 + fmt.Println("The third number is: ", numbers["three"]) // obtém valores + // Isto imprime: The third number is: 3 -Some notes when you use map. +Algumas notas sobre o uso de map. -- `map` is disorderly. Everytime you print `map` you will get different results. It's impossible to get values by `index` -you have to use `key`. -- `map` doesn't have a fixed length. It's a reference type just like `slice`. -- `len` works for `map` also. It returns how many `key`s that map has. -- It's quite easy to change the value through `map`. Simply use `numbers["one"]=11` to change the value of `key` one to `11`. +- `map` é desordenado. Toda vez que você imprime `map` você terá resultados diferentes. É impossível obter valores por `índice` -você precisa utilizar `chave`. +- `map` não tem um comprimento fixo. É um tipo de referência, assim como o `slice`. +- `len` também funciona para `map`. Isto retorna quantas `chave`s o map tem. +- É muito fácil alterar valores utilizando `map`. Basta usar `numbers["one"]=11` para alterar o valor da `chave` one para `11`. -You can use form `key:val` to initialize map's values, and `map` has built-in methods to check if the `key` exists. +Você pode usar a forma `chave:valor` para inicializar valores em um `map`, pois `map` possui métodos embutidos para verificar se a `chave` existe. -Use `delete` to delete an element in `map`. +Use `delete` para deletar um elemento em um `map`. - // Initialize a map + // Inicializa um map rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 } - // map has two return values. For the second return value, if the key doesn't exist,'ok' returns false. It returns true otherwise. + // map possui dois valores de retorno. Caso a chave não exista, o segundo valor de retorno, neste caso recebido pela variável 'ok', será falso (false). Caso contrário será verdadeiro (true). csharpRating, ok := rating["C#"] if ok { fmt.Println("C# is in the map and its rating is ", csharpRating) @@ -406,49 +408,49 @@ Use `delete` to delete an element in `map`. fmt.Println("We have no rating associated with C# in the map") } - delete(rating, "C") // delete element with key "c" + delete(rating, "C") // deleta o elemento com a chave "c" -As I said above, `map` is a reference type. If two `map`s point to same underlying data, any change will affect both of them. +Como foi dito acima, `map` é um tipo de referência. Se dois `map`s apontam para o mesmo dado subjacente, qualquer alteração irá afetar ambos. m := make(map[string]string) m["Hello"] = "Bonjour" m1 := m - m1["Hello"] = "Salut" // now the value of m["hello"] is Salut + m1["Hello"] = "Salut" // agora o valor de m["hello"] é Salut ### make, new -`make` does memory allocation for built-in models, such as `map`, `slice`, and `channel`, while `new` is for types' memory allocation. +`make` realiza alocação de memória para modelos internos, como `map`, `slice`, e `channel`, enquanto `new` é utilizado para alocação de memória de tipos. -`new(T)` allocates zero-value to type `T`'s memory, returns its memory address, which is the value of type `*T`. By Go's definition, it returns a pointer which points to type `T`'s zero-value. +`new(T)` aloca a memória para o valor zero do tipo `T` e retorna seu endereço de memória, que é o valor do tipo `*T`. Por definição, isto retorna um ponteiro que aponta para o valor zero de `T`. -`new` returns pointers. +`new` retorna ponteiros. -The built-in function `make(T, args)` has different purposes than `new(T)`. `make` can be used for `slice`, `map`, and `channel`, and returns a type `T` with an initial value. The reason for doing this is because the underlying data of these three types must be initialized before they point to them. For example, a `slice` contains a pointer that points to the underlying `array`, length and capacity. Before these data are initialized, `slice` is `nil`, so for `slice`, `map` and `channel`, `make` initializes their underlying data and assigns some suitable values. +A função interna `make(T, args)` possui diferentes propósitos se comparado a `new(T)`. `make` pode ser usado para `slice`, `map`, e `channel`, e retorna o tipo `T` com um valor inicial. A razão para fazer isto é porque os dados subjacentes destes três tipos devem ser inicializados antes de apontar para eles. Por exemplo, um `slice` contém um ponteiro que aponta para um `array` subjacente, comprimento e capacidade. Antes que estes dados sejam inicializados, `slice` é `nil`, então, para `slice`, `map` e `channel`, `make` inicializa seus dados subjacentes e atribui alguns valores adequados. -`make` returns non-zero values. +`make` retorna valores diferentes de zero. -The following picture shows how `new` and `make` are different. +A seguinte imagem mostra como `new` e `make` são diferentes. ![](images/2.2.makenew.png?raw=true) -Figure 2.5 Underlying memory allocation of make and new +Figure 2.5 Alocação de memória para make e new -Zero-value does not mean empty value. It's the value that variables default to in most cases. Here is a list of some zero-values. +Valor zero não significa valor vazio. Na maioria dos casos é o valor padrão das variáveis. Aqui está uma lista de alguns valores zero. int 0 int8 0 int32 0 int64 0 uint 0x0 - rune 0 // the actual type of rune is int32 - byte 0x0 // the actual type of byte is uint8 - float32 0 // length is 4 byte - float64 0 //length is 8 byte + rune 0 // o tipo real de rune é int32 + byte 0x0 // o tipo real de byte é uint8 + float32 0 // comprimento é 4 bytes + float64 0 // comprimento é 8 bytes bool false string "" ## Links -- [Directory](preface.md) -- Previous section: ["Hello, Go"](02.1.md) -- Next section: [Control statements and functions](02.3.md) +- [Sumário](preface.md) +- Sessão anterior: ["Hello, Go"](02.1.md) +- Próxima sessão: [Control statements and functions](02.3.md) From 2db6d163d59a5a5210b37d0ad8195c649fc43879 Mon Sep 17 00:00:00 2001 From: "Kelvin S. do Prado" Date: Sat, 26 Nov 2016 17:40:38 -0200 Subject: [PATCH 14/32] Translation of code from section 2.2 to Portuguese (PT_BR). --- pt-br/code/src/apps/ch.2.2/main.go | 148 +++++++++--------- .../ch.2.2/what_is_wrong_with_this/main.go | 6 +- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/pt-br/code/src/apps/ch.2.2/main.go b/pt-br/code/src/apps/ch.2.2/main.go index 5b54b9c5..8f8253a0 100644 --- a/pt-br/code/src/apps/ch.2.2/main.go +++ b/pt-br/code/src/apps/ch.2.2/main.go @@ -1,5 +1,5 @@ -// Example code for Chapter 2.2 from "Build Web Application with Golang" -// Purpose: Goes over the assignment and manipulation of basic data types. +// Código de exemplo para o Capítulo 2.2 do "Build Web Application with Golang" +// Propósito: Revisar os conceitos de atribuição e manipulação de tipos de dados básicos. package main import ( @@ -7,14 +7,14 @@ import ( "fmt" ) -// constants +// constantes const Pi = 3.1415926 -// booleans default to `false` -var isActive bool // global variable -var enabled, disabled = true, false // omit type of variables +// booleanos: padrão `false` +var isActive bool // variável global +var enabled, disabled = true, false // omite o tipo das variáveis -// grouped definitions +// definições agrupadas const ( i = 1e4 MaxThread = 10 @@ -22,24 +22,24 @@ const ( ) var ( - frenchHello string // basic form to define string - emptyString string = "" // define a string with empty string + frenchHello string // forma básica para definir strings + emptyString string = "" // define uma string vazia ) func show_multiple_assignments() { fmt.Println("show_multiple_assignments()") var v1 int = 42 - // Define three variables with type "int", and initialize their values. - // vname1 is v1, vname2 is v2, vname3 is v3 + // Define três variáveis com o tipo "int" e inicializa seus valores. + // vname1 é v1, vname2 é v2, vname3 é v3 var v2, v3 int = 2, 3 - // `:=` only works in functions - // `:=` is the short way of declaring variables without - // specifying the type and using the keyboard `var`. + // `:=` funciona somente em funções + // `:=` é a maneira curta de declarar variáveis sem + // especificar o tipo e usando a palvra-chave `var`. vname1, vname2, vname3 := v1, v2, v3 - // `_` disregards the returned value. + // `_` desconsidera o valor retornado. _, b := 34, 35 fmt.Printf("vname1 = %v, vname2 = %v, vname3 = %v\n", vname1, vname2, vname3) @@ -48,9 +48,9 @@ func show_multiple_assignments() { } func show_bool() { fmt.Println("show_bool()") - var available bool // local variable - valid := false // Shorthand assignment - available = true // assign value to variable + var available bool // variável local + valid := false // declara a variável e infere o tipo booleano (declaração curta) + available = true // atribui um valor a variável fmt.Printf("valid = %v, !valid = %v\n", valid, !valid) fmt.Printf("available = %v\n", available) @@ -78,14 +78,14 @@ func show_different_types() { } func show_strings() { fmt.Println("show_strings()") - no, yes, maybe := "no", "yes", "maybe" // brief statement + no, yes, maybe := "no", "yes", "maybe" // declaração curta japaneseHello := "Ohaiyou" - frenchHello = "Bonjour" // basic form of assign values + frenchHello = "Bonjour" // forma básica de atribuir valores fmt.Println("Random strings") fmt.Println(frenchHello, japaneseHello, no, yes, maybe) - // The backtick, `, will not escape any character in a string + // A crase, `, não deixa escapar qualquer caractere da string fmt.Println(`This is on multiple lines`) @@ -94,18 +94,18 @@ func show_string_manipulation() { fmt.Println("show_string_manipulation()") var s string = "hello" - //You can't do this with strings + //Você não pode fazer isso com strings //s[0] = 'c' s = "hello" - c := []byte(s) // convert string to []byte type + c := []byte(s) // converte string para o tipo []byte c[0] = 'c' - s2 := string(c) // convert back to string type + s2 := string(c) // converte novamente para o tipo string m := " world" a := s + m - d := "c" + s[1:] // you cannot change string values by index, but you can get values instead. + d := "c" + s[1:] // você não pode alterar valores de string pelo índice, mas você pode obter os valores desta maneira fmt.Printf("%s\n", d) fmt.Printf("s = %s, c = %v\n", s, c) @@ -125,66 +125,66 @@ func show_iota() { x = iota // x == 0 y = iota // y == 1 z = iota // z == 2 - w // If there is no expression after constants name, - // it uses the last expression, so here is saying w = iota implicitly. - // Therefore w == 3, and y and x both can omit "= iota" as well. + w // Se não houver nenhuma expressão após o nome da constante, + // ela usa a última expressão, ou seja, neste caso w = iota implicitamente. + // Portanto w == 3, e tanto y quanto z podem omitir "= iota" também. ) - const v = iota // once iota meets keyword `const`, it resets to `0`, so v = 0. + const v = iota // uma vez que iota encontra a palavra-chave `const`, ela é redefinida para `0`, então v = 0. const ( - e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line. + e, f, g = iota, iota, iota // e=0,f=0,g=0 valores de iota são iguais quando estão na mesma linha. ) fmt.Printf("x = %v, y = %v, z = %v, w = %v\n", x, y, z, w) fmt.Printf("v = %v\n", v) fmt.Printf("e = %v, f = %v, g = %v\n", e, f, g) } -// Functions and variables starting with a capital letter are public to other packages. -// Everything else is private. +// Funções e variáveis começando com uma letra maiúscula são públicas para outros pacotes. +// Todo o resto é privado. func This_is_public() {} func this_is_private() {} func set_default_values() { - // default values for the types. + // valores padrão para os tipos. const ( a int = 0 b int8 = 0 c int32 = 0 d int64 = 0 e uint = 0x0 - f rune = 0 // the actual type of rune is int32 - g byte = 0x0 // the actual type of byte is uint8 - h float32 = 0 // length is 4 byte - i float64 = 0 //length is 8 byte + f rune = 0 // o tipo real de rune é int32 + g byte = 0x0 // o tipo real de byte é uint8 + h float32 = 0 // comprimento é 4 bytes + i float64 = 0 // comprimento é 8 bytes j bool = false k string = "" ) } func show_arrays() { fmt.Println("show_arrays()") - var arr [10]int // an array of type int - arr[0] = 42 // array is 0-based - arr[1] = 13 // assign value to element + var arr [10]int // um array do tipo int + arr[0] = 42 // array é baseado em 0 + arr[1] = 13 // atribui valor ao elemento - a := [3]int{1, 2, 3} // define a int array with 3 elements + a := [3]int{1, 2, 3} // define um array do tipo int com 3 elementos b := [10]int{1, 2, 3} - // define a int array with 10 elements, - // and first three are assigned, rest of them use default value 0. + // define um array do tipo int com 10 elementos, + // e os três primeiros são atribuídos, o restante usa o valor padrão 0. - c := [...]int{4, 5, 6} // use `…` replace with number of length, Go will calculate it for you. + c := [...]int{4, 5, 6} // usa `…` para substituir o número do comprimento, Go irá calcular isto para você. - // define a two-dimensional array with 2 elements, and each element has 4 elements. + // define um array bidimensional com 2 elementos, e onde cada elemento possui 4 elementos. doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} - // You can write about declaration in a shorter way. + // Você pode escrever a declaração de forma curta. easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} fmt.Println("arr =", arr) - fmt.Printf("The first element is %d\n", arr[0]) // get element value, it returns 42 + fmt.Printf("The first element is %d\n", arr[0]) // obtém o valor do elemento, retorna 42 fmt.Printf("The last element is %d\n", arr[9]) - //it returns default value of 10th element in this array, which is 0 in this case. + // retorna o valor padrão do décimo elemento do array, que neste caso é 0. fmt.Println("array a =", a) fmt.Println("array b =", b) @@ -195,36 +195,36 @@ func show_arrays() { } func show_slices() { fmt.Println("show_slices()") - // define a slice with 10 elements which types are byte + // define um slice de tipo byte com 10 elementos var ar = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - // define two slices with type []byte + // define dois slices com o tipo []byte var a, b []byte - // a points to elements from 3rd to 5th in array ar. + // a aponta para os elementos da posição 3 até a 5 do array ar. a = ar[2:5] - // now a has elements ar[2]、ar[3] and ar[4] + // agora a possui os elementos ar[2], ar[3] e ar[4] - // b is another slice of array ar + // b é outro slice do array ar b = ar[3:5] - // now b has elements ar[3] and ar[4] + // agora b possui os elementos de ar[3] e ar[4] - // define an array + // define um array var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} - // define two slices + // define dois slices var aSlice, bSlice []byte - // some convenient operations - aSlice = array[:3] // equals to aSlice = array[0:3] aSlice has elements a,b,c - aSlice = array[5:] // equals to aSlice = array[5:10] aSlice has elements f,g,h,i,j - aSlice = array[:] // equals to aSlice = array[0:10] aSlice has all elements + // algumas operações convenientes + aSlice = array[:3] // igual a aSlice = array[0:3] aSlice possui os elementos a,b,c + aSlice = array[5:] // igual a aSlice = array[5:10] aSlice possui os elementos f,g,h,i,j + aSlice = array[:] // igual a aSlice = array[0:10] aSlice possui todos os elementos - // slice from slice - aSlice = array[3:7] // aSlice has elements d,e,f,g,len=4,cap=7 - bSlice = aSlice[1:3] // bSlice contains aSlice[1], aSlice[2], so it has elements e,f - bSlice = aSlice[:3] // bSlice contains aSlice[0], aSlice[1], aSlice[2], so it has d,e,f - bSlice = aSlice[0:5] // slcie could be expanded in range of cap, now bSlice contains d,e,f,g,h - bSlice = aSlice[:] // bSlice has same elements as aSlice does, which are d,e,f,g + // slice de slice + aSlice = array[3:7] // aSlice possui os elementos d,e,f,g,len=4,cap=7 + bSlice = aSlice[1:3] // bSlice contém aSlice[1], aSlice[2], ou seja, ele possui os elementos e,f + bSlice = aSlice[:3] // bSlice contém aSlice[0], aSlice[1], aSlice[2], ou seja, ele possui os elementos d,e,f + bSlice = aSlice[0:5] // bSlice pode ser expandido de acordo com cap, agora bSlice contém d,e,f,g,h + bSlice = aSlice[:] // bSlice possui os mesmos elementos de aSlice, os quais são d,e,f,g fmt.Println("slice ar =", ar) fmt.Println("slice a =", a) @@ -236,22 +236,22 @@ func show_slices() { } func show_map() { fmt.Println("show_map()") - // use string as key type, int as value type, and you have to use `make` initialize it. + // use tipo string para a chave, tipo int para o valor, e você precisa usar `make` para inicializar var numbers map[string]int - // another way to define map + // outra forma de declarar map numbers = make(map[string]int) - numbers["one"] = 1 // assign value by key + numbers["one"] = 1 // atribui valor pela chave numbers["ten"] = 10 numbers["three"] = 3 - // Initialize a map + // Inicializa um map rating := map[string]float32{"C": 5, "Go": 4.5, "Python": 4.5, "C++": 2} fmt.Println("map numbers =", numbers) - fmt.Println("The third number is: ", numbers["three"]) // get values - // It prints: The third number is: 3 + fmt.Println("The third number is: ", numbers["three"]) // obtém os valores + // Isto irá imprimir: The third number is: 3 - // map has two return values. For second value, if the key doesn't exist,ok is false,true otherwise. + // map possui dois valores de retorno. Se a chave não existir, o segundo valor, neste caso "ok", será falso (false). Caso contrário será verdadeiro (true). csharpRating, ok := rating["C#"] if ok { fmt.Println("C# is in the map and its rating is ", csharpRating) @@ -259,7 +259,7 @@ func show_map() { fmt.Println("We have no rating associated with C# in the map") } - delete(rating, "C") // delete element with key "c" + delete(rating, "C") // deleta o elemento com a chave "c" fmt.Printf("map rating = %#v\n", rating) } func main() { diff --git a/pt-br/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go b/pt-br/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go index b435f038..4c3b5a92 100644 --- a/pt-br/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go +++ b/pt-br/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go @@ -1,6 +1,6 @@ -// Example code for Chapter 2.2 from "Build Web Application with Golang" -// Purpose: Try to fix this program. -// From the console, type `go run main.go` +// Código de exemplo para o Capítulo 2.2 do "Build Web Application with Golang" +// Propósito: Tente corrigir este programa. +// No console, digite `go run main.go` package main func main() { From 9c76201b492ffcbc9e08ec8659a2ae917fd1b2b2 Mon Sep 17 00:00:00 2001 From: "Kelvin S. do Prado" Date: Sat, 26 Nov 2016 17:53:40 -0200 Subject: [PATCH 15/32] Review of the section 2.2 translation. Update the SUMMARY and preface files. --- pt-br/02.2.md | 8 ++++---- pt-br/SUMMARY.md | 2 +- pt-br/preface.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pt-br/02.2.md b/pt-br/02.2.md index a6fd793e..5b4a9419 100644 --- a/pt-br/02.2.md +++ b/pt-br/02.2.md @@ -1,4 +1,4 @@ -# 2.2 Fundamentos Go +# 2.2 Fundamentos em Go Nesta seção vamos aprender como definir constantes, variáveis com tipos elementares e algumas habilidades de programação em Go. @@ -117,7 +117,7 @@ Sua forma é `RE+IMi`, onde `RE` é a parte real e `IM` é a parte imaginária, ### String -Nós apenas falamos sobre como a linguagem Go utiliza o conjunto de caracteres UTF-8. As strings são representadas por aspas duplas `""` ou crases (backticks) ``` `` ```. +Nós falamos apenas sobre como a linguagem Go utiliza o conjunto de caracteres UTF-8. As strings são representadas por aspas duplas `""` ou crases (backticks) ``` `` ```. // código de amostra var frenchHello string // forma básica de definir string @@ -452,5 +452,5 @@ Valor zero não significa valor vazio. Na maioria dos casos é o valor padrão d ## Links - [Sumário](preface.md) -- Sessão anterior: ["Hello, Go"](02.1.md) -- Próxima sessão: [Control statements and functions](02.3.md) +- Seção anterior: ["Hello, Go"](02.1.md) +- Próxima seção: [Declarações de controle e funções](02.3.md) diff --git a/pt-br/SUMMARY.md b/pt-br/SUMMARY.md index 726f6111..2483a391 100644 --- a/pt-br/SUMMARY.md +++ b/pt-br/SUMMARY.md @@ -6,7 +6,7 @@ * [Resumo](01.5.md) * [Conhecimento básico de Go](02.0.md) * [Hello, Go](02.1.md) - * [Go foundation](02.2.md) + * [Fundamentos em Go](02.2.md) * [Control statements and functions](02.3.md) * [struct](02.4.md) * [Object-oriented](02.5.md) diff --git a/pt-br/preface.md b/pt-br/preface.md index f3f14c5e..f60327ad 100644 --- a/pt-br/preface.md +++ b/pt-br/preface.md @@ -6,7 +6,7 @@ - 1.5. [Sumário](01.5.md) - 2.[Go, conhecimento básico](02.0.md) - 2.1. ["Olá, Go"](02.1.md) - - 2.2. [Go foundation](02.2.md) + - 2.2. [Fundamentos em Go](02.2.md) - 2.3. [Control statements and functions](02.3.md) - 2.4. [struct](02.4.md) - 2.5. [Orientação a Objetos](02.5.md) From 79e292f71e9889eef81abe294675fe134291395d Mon Sep 17 00:00:00 2001 From: knarfeh Date: Mon, 28 Nov 2016 23:47:25 +0800 Subject: [PATCH 16/32] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=B8=AD=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E6=A0=87=E7=82=B9=E6=B7=B7=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zh/02.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zh/02.3.md b/zh/02.3.md index 551ccf94..71189b59 100644 --- a/zh/02.3.md +++ b/zh/02.3.md @@ -3,7 +3,7 @@ ## 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑。Go中流程控制分三大类:条件判断,循环控制和无条件跳转。 ### if -`if`也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事。 +`if`也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事。 Go里面`if`条件判断语句中不需要括号,如下代码所示 From 4075b93d2ca531fcc33ca89bc4ad1d4e19bd4308 Mon Sep 17 00:00:00 2001 From: Kelvin Salton do Prado Date: Tue, 29 Nov 2016 12:04:47 -0200 Subject: [PATCH 17/32] Fixed some duplicate words in the English version. --- en/02.1.md | 2 +- en/06.4.md | 2 +- en/09.1.md | 4 ++-- en/09.4.md | 2 +- en/12.4.md | 4 ++-- en/13.1.md | 2 +- en/14.6.md | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/en/02.1.md b/en/02.1.md index fb21f6ed..bc8b1775 100644 --- a/en/02.1.md +++ b/en/02.1.md @@ -17,7 +17,7 @@ While this might seem to be a shallow problem at the top, but when the codebase For other languages there are many variables when it comes to writing code, every language is good for its use case, but Go is a little special in that turf because it was designed at a company which is the very synonym of the Internet (and distributed computing), typically the flow of writing code goes from Python to Java to C++ for optimization purposes, but the problem is that almost all languages which are widely in use right now were written decades ago when 1GB storage came at a much higher price compared to now, where storage and computing has gotten cheap. Computers are getting multiples cores these days and the "old languages" don't harness concurrency in a way that go does, not because those languages are bad, but simply because that usecase wasn't relevant when the languages evolved. -So to mitigate all the problems that Google faced with the current tools, they wrote a systems language called Go, which you are about to learn! There are many many advantages to using golang, and there might be disadvantages too for every coin has both sides. But significant improvements in places like code formatting, since they designed the language in such a way that there won't be wars on how to format code, the gocode written by anyone in the world (assuming they know and use `gofmt`) will look exactly the same, this won't seem to matter until you work in a team! also when the company uses automated code review or some other fancy technique then in other languages which don't have strict and standard formatting rules then the code might get screwed up, but not in go! +So to mitigate all the problems that Google faced with the current tools, they wrote a systems language called Go, which you are about to learn! There are many advantages to using golang, and there might be disadvantages too for every coin has both sides. But significant improvements in places like code formatting, since they designed the language in such a way that there won't be wars on how to format code, the gocode written by anyone in the world (assuming they know and use `gofmt`) will look exactly the same, this won't seem to matter until you work in a team! also when the company uses automated code review or some other fancy technique then in other languages which don't have strict and standard formatting rules then the code might get screwed up, but not in go! Go was designed with concurrency in mind, please note that parallelism != concurrency, there is an amazing post by Rob Pike on the golang blog, blog.golang.org, you will find it there, it is worth a read. diff --git a/en/06.4.md b/en/06.4.md index 658f37c1..48740086 100644 --- a/en/06.4.md +++ b/en/06.4.md @@ -49,7 +49,7 @@ Refresh the page and you'll see the following: Figure 6.7 hijacking the session has succeeded. -Here we see that we can hijack sessions between different browsers, and actions performed in one one browser can affect the state of a page in another browser. Because HTTP is stateless, there is no way of knowing that the session id from firefox is simulated, and chrome is also not able to know that it's session id has been hijacked. +Here we see that we can hijack sessions between different browsers, and actions performed in one browser can affect the state of a page in another browser. Because HTTP is stateless, there is no way of knowing that the session id from firefox is simulated, and chrome is also not able to know that it's session id has been hijacked. ## prevent session hijacking diff --git a/en/09.1.md b/en/09.1.md index 8f4bc738..1301535c 100644 --- a/en/09.1.md +++ b/en/09.1.md @@ -21,7 +21,7 @@ As can be seen from the figure, to complete a CSRF attack, the victim must compl -1. Log into trusted site A, and store a local Cookie. -2. Without going through existing site A, access the dangerous link to site B. -As a reader you may be asking: "If I do not meet the above two conditions, I will will not be subjected to CSRF attacks." Yes this is true, however you cannot guarantee that the following does not occur: +As a reader you may be asking: "If I do not meet the above two conditions, I will not be subjected to CSRF attacks." Yes this is true, however you cannot guarantee that the following does not occur: - You cannot guarantee that when you are logged into a site, the site didn't launch any hidden tabs. - You cannot guarantee that when you close your browser, your cookies will immediately expire and your last session will have ended. @@ -37,7 +37,7 @@ You might be a little scared after reading the section above. But fear is a good Preventative measures against CSRF attacks can be taken on both the server and client sides of a web application. However, CSRF attacks are most effectively thwarted on the server side. -There are many ways of preventing CSRF attacks on the server side. Most approaches stem from from the following two aspects: +There are many ways of preventing CSRF attacks on the server side. Most approaches stem from the following two aspects: 1. Maintaining proper use of GET, POST and cookies. 2. Including a pseudo-random number with non-GET requests. diff --git a/en/09.4.md b/en/09.4.md index d8823175..d6bbe9bd 100644 --- a/en/09.4.md +++ b/en/09.4.md @@ -60,7 +60,7 @@ SQL injection attacks can be devastating -how can do we even begin to defend aga 1. Strictly limit permissions for database operations so that users only have the minimum set of permissions required to accomplish their work, thus minimizing the risk of database injection attacks. 2. Check that input data has the expected data format, and strictly limit the types of variables that can be submitted. This can involve regexp matching, or using the strconv package to convert strings into other basic types for sanitization and evaluation. 3. Transcode or escape from pairs of special characters ( '"\&*; etc. ) before persisting them into the database. Go's `text/template` package has a `HTMLEscapeString` function that can be used to return escaped HTML. -4. Use your database's parameterized query interface. Parameterized statements use parameters instead of concatenating user input variables in embedded SQL statements; in other words, they do not directly splice ​​SQL statements. For example, using the the `Prepare` function in Go's `database/sql` package, we can create prepared statements for later execution with `Query` or `Exec(query string, args... interface {})`. +4. Use your database's parameterized query interface. Parameterized statements use parameters instead of concatenating user input variables in embedded SQL statements; in other words, they do not directly splice ​​SQL statements. For example, using the `Prepare` function in Go's `database/sql` package, we can create prepared statements for later execution with `Query` or `Exec(query string, args... interface {})`. 5. Before releasing your application, thoroughly test it using professional tools for detecting SQL injection vulnerabilities and to repair them, if they exist. There are many online open source tools that do just this, such as sqlmap, SQLninja, to name a few. 6. Avoid printing out SQL error information on public webpages. Attackers can use these error messages to carry out SQL injection attacks. Examples of such errors are type errors, fields not matching errors, or any errors containing SQL statements. diff --git a/en/12.4.md b/en/12.4.md index 327cc6ab..6babaf26 100644 --- a/en/12.4.md +++ b/en/12.4.md @@ -1,6 +1,6 @@ # 12.4 Backup and recovery -In this section, we'll discuss another aspect of application management: data backup and recovery on production servers. We often encounter situations where production servers don't behave as as we expect them to. Server network outages, hard drive malfunctions, operating system crashes and other similar events can cause databases to become unavailable. The need to recover from these types of events has led to the emergence of many cold standby/hot standby tools that can help to facilitate disaster recovery remotely. In this section, we'll explain how to backup deployed applications in addition to backing up and restoring any MySQL and Redis databases you might be using. +In this section, we'll discuss another aspect of application management: data backup and recovery on production servers. We often encounter situations where production servers don't behave as we expect them to. Server network outages, hard drive malfunctions, operating system crashes and other similar events can cause databases to become unavailable. The need to recover from these types of events has led to the emergence of many cold standby/hot standby tools that can help to facilitate disaster recovery remotely. In this section, we'll explain how to backup deployed applications in addition to backing up and restoring any MySQL and Redis databases you might be using. ## Application Backup @@ -174,7 +174,7 @@ As you can see, importing and exporting database is a fairly simple matter. If y ## Redis backup -Redis is one of the most popular NoSQL databases, and both hot and cold backup techniques can also be used in systems which use it. Like MySQL, Redis also supports master/slave mode, which is ideal for implementing hot backups (refer to Redis' official documentation to learn learn how to configure this; the process is very straightforward). As for cold backups, Redis routinely saves cached data in memory to the database file on-disk. We can simply use the rsync backup method described above to synchronize it with a non-local machine. +Redis is one of the most popular NoSQL databases, and both hot and cold backup techniques can also be used in systems which use it. Like MySQL, Redis also supports master/slave mode, which is ideal for implementing hot backups (refer to Redis' official documentation to learn how to configure this; the process is very straightforward). As for cold backups, Redis routinely saves cached data in memory to the database file on-disk. We can simply use the rsync backup method described above to synchronize it with a non-local machine. ## Redis recovery diff --git a/en/13.1.md b/en/13.1.md index b024de93..4ccb1585 100644 --- a/en/13.1.md +++ b/en/13.1.md @@ -4,7 +4,7 @@ Anything you intend to do well must first be planned well. In our case, our inte ## GOPATH and project settings -Let's proceed by assuming that our GOPATH points to a folder with with an ordinary directory name (if not, we can easily set up a suitable directory and set its path as the GOPATH). As we've describe earlier, a GOPATH can contain more than one directory: in Windows, we can set this as an environment variable; in linux/OSX systems, GOPATH can be set using `export`, i.e: `export gopath=/path/to/your/directory`, as long as the directory which GOPATH points to contains the three sub-directories: `pkg`, `bin` and `src`. Below, we've placed the source code of our new project in the `src` directory with the tentative name `beelog`. Here are some screenshots of the Windows environment variables as well as of the directory structure. +Let's proceed by assuming that our GOPATH points to a folder with an ordinary directory name (if not, we can easily set up a suitable directory and set its path as the GOPATH). As we've describe earlier, a GOPATH can contain more than one directory: in Windows, we can set this as an environment variable; in linux/OSX systems, GOPATH can be set using `export`, i.e: `export gopath=/path/to/your/directory`, as long as the directory which GOPATH points to contains the three sub-directories: `pkg`, `bin` and `src`. Below, we've placed the source code of our new project in the `src` directory with the tentative name `beelog`. Here are some screenshots of the Windows environment variables as well as of the directory structure. ![](images/13.1.gopath.png?raw=true) diff --git a/en/14.6.md b/en/14.6.md index 5ad61fc9..0bae3163 100644 --- a/en/14.6.md +++ b/en/14.6.md @@ -10,7 +10,7 @@ In fact, `net/http/pprof` simply exposes runtime profiling data from the `runtim ## pprof support in Beego -The Beego framework currently supports pprof, however it is not not turned on by default. If you need to test the performance of your application, (for instance by viewing the execution goroutine) such information from Go's default package "net/http/pprof" already has this feature. Because beego has repackaged the ServHTTP function, you can not open the default feature included in pprof. This resulted in beego supporting pprof internally. +The Beego framework currently supports pprof, however it is not turned on by default. If you need to test the performance of your application, (for instance by viewing the execution goroutine) such information from Go's default package "net/http/pprof" already has this feature. Because beego has repackaged the ServHTTP function, you can not open the default feature included in pprof. This resulted in beego supporting pprof internally. - First in our `beego.Run` function, we choose whether or not to automatically load the performance pack according to our configuration variable (in this case, PprofOn): From 1b89bfd4b779d5f719dccfcb699789d40ddb3ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=A3=E5=90=9B?= Date: Wed, 7 Dec 2016 18:25:37 +0800 Subject: [PATCH 18/32] =?UTF-8?q?.=E5=8F=AA=E8=83=BD=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E4=BB=BB=E6=84=8F=E5=AD=97=E7=AC=A6=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 要匹配由数字和字母组成的字符,需要使用"^[a-zA-Z0-9]+$","^[a-zA-Z0-9]+."只能匹配由数字字母开头和一个任意字符组成的两个长度的字符串。 --- zh/09.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zh/09.2.md b/zh/09.2.md index e3b1d55a..58f97fdb 100644 --- a/zh/09.2.md +++ b/zh/09.2.md @@ -59,7 +59,7 @@ r.ParseForm() username := r.Form.Get("username") CleanMap := make(map[string]interface{}, 0) - if ok, _ := regexp.MatchString("^[a-zA-Z0-9].$", username); ok { + if ok, _ := regexp.MatchString("^[a-zA-Z0-9]+$", username); ok { CleanMap["username"] = username } From ba5d160a9c3ceace8dfd849496dd80da2985faee Mon Sep 17 00:00:00 2001 From: vCaesar Date: Fri, 9 Dec 2016 01:18:48 +0800 Subject: [PATCH 19/32] Fix SQL Error --- zh/05.2.md | 6 ++++-- zh/05.3.md | 3 ++- zh/05.4.md | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/zh/05.2.md b/zh/05.2.md index cbf68ca1..d1fb09c2 100644 --- a/zh/05.2.md +++ b/zh/05.2.md @@ -23,7 +23,7 @@ Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持data `departname` VARCHAR(64) NULL DEFAULT NULL, `created` DATE NULL DEFAULT NULL, PRIMARY KEY (`uid`) - ) + ); CREATE TABLE `userdetail` ( `uid` INT(10) NOT NULL DEFAULT '0', @@ -33,6 +33,7 @@ Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持data ) 如下示例将示范如何使用database/sql接口对数据库表进行增删改查操作 +```Go package main @@ -108,7 +109,8 @@ Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持data panic(err) } } - + +``` 通过上面的代码我们可以看出,Go操作Mysql数据库是很方便的。 diff --git a/zh/05.3.md b/zh/05.3.md index 4457a986..5b30c194 100644 --- a/zh/05.3.md +++ b/zh/05.3.md @@ -29,6 +29,7 @@ Go支持sqlite的驱动也比较多,但是好多都是不支持database/sql接 ); 看下面Go程序是如何操作数据库表数据:增删改查 +```Go package main @@ -104,7 +105,7 @@ Go支持sqlite的驱动也比较多,但是好多都是不支持database/sql接 panic(err) } } - +``` 我们可以看到上面的代码和MySQL例子里面的代码几乎是一模一样的,唯一改变的就是导入的驱动改变了,然后调用`sql.Open`是采用了SQLite的方式打开。 diff --git a/zh/05.4.md b/zh/05.4.md index 02a4b2fa..b94c8c10 100644 --- a/zh/05.4.md +++ b/zh/05.4.md @@ -38,12 +38,14 @@ Go实现的支持PostgreSQL的驱动也很多,因为国外很多人在开发 看下面这个Go如何操作数据库表数据:增删改查 -package main +```Go + + package main import ( "database/sql" "fmt" - _ "https://github.com/lib/pq" + _ "github.com/lib/pq" ) func main() { @@ -58,10 +60,15 @@ package main checkErr(err) //pg不支持这个函数,因为他没有类似MySQL的自增ID - id, err := res.LastInsertId() - checkErr(err) + // id, err := res.LastInsertId() + // checkErr(err) + // fmt.Println(id) + + var lastInsertId int + err = db.QueryRow("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;", "astaxie", "研发部门", "2012-12-09").Scan(&lastInsertId) + checkErr(err) + fmt.Println("最后插入id =", lastInsertId) - fmt.Println(id) //更新数据 stmt, err = db.Prepare("update userinfo set username=$1 where uid=$2") @@ -113,6 +120,7 @@ package main panic(err) } } +``` 从上面的代码我们可以看到,PostgreSQL是通过`$1`,`$2`这种方式来指定要传递的参数,而不是MySQL中的`?`,另外在sql.Open中的dsn信息的格式也与MySQL的驱动中的dsn格式不一样,所以在使用时请注意它们的差异。 From c3637d2ad7c0b39ed69de4ecf3065c1cb6f5e549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=A3=E5=90=9B?= Date: Fri, 9 Dec 2016 14:20:07 +0800 Subject: [PATCH 20/32] =?UTF-8?q?keepalive=E4=BD=9C=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit keepalive并不是为了让tcp保持长连接,而只是一种让操作系统可以自动检测连接意外断开的机制,一个连接保持长连接是因为建立之后没有断开,而不是因为设置了keepalive。 --- zh/08.1.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zh/08.1.md b/zh/08.1.md index fc9a9ea8..3cc07558 100644 --- a/zh/08.1.md +++ b/zh/08.1.md @@ -302,8 +302,7 @@ TCP有很多连接控制函数,我们平常用到比较多的有如下几个 用来设置写入/读取一个连接的超时时间。当超过设置时间时,连接自动关闭。 func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error - -设置客户端是否和服务器端保持长连接,可以降低建立TCP连接时的握手开销,对于一些需要频繁交换数据的应用场景比较适用。 +设置keepAlive属性,是操作系统层在tcp上没有数据和ACK的时候,会间隔性的发送keepalive包,操作系统可以通过该包来判断一个tcp连接是否已经断开,在windows上默认2个小时没有收到数据和keepalive包的时候人为tcp连接已经断开,这个功能和我们通常在应用层加的心跳包的功能类似。 更多的内容请查看`net`包的文档。 ## UDP Socket From 0662bda81984526fdc57f15dbd87668c39754824 Mon Sep 17 00:00:00 2001 From: yihf Date: Sat, 10 Dec 2016 16:54:43 +0800 Subject: [PATCH 21/32] Update 08.3.md --- zh/08.3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zh/08.3.md b/zh/08.3.md index 3bae24fb..109e827f 100644 --- a/zh/08.3.md +++ b/zh/08.3.md @@ -90,7 +90,7 @@ Go没有为REST提供直接支持,但是因为RESTful是基于HTTP协议实现 func adduser(w http.ResponseWriter, r *http.Request) { uid := r.FormValue("uid") - fmt.Fprint(w, "you are add user %s", uid) + fmt.Fprintf(w, "you are add user %s", uid) } func main() { From ad37816a0f8e6b45cf1e5adbc788d1f2fdffb3c0 Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sat, 10 Dec 2016 17:51:44 +0800 Subject: [PATCH 22/32] Add syntax highlighting --- zh/02.1.md | 4 +- zh/02.2.md | 121 +++++++++++++++++++++++++++++------------------------ 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/zh/02.1.md b/zh/02.1.md index 5bc0e69f..a5a1a7b9 100644 --- a/zh/02.1.md +++ b/zh/02.1.md @@ -7,7 +7,7 @@ 这就像一个传统,在学习大部分语言之前,你先学会如何编写一个可以输出`hello world`的程序。 准备好了吗?Let's Go! - +```Go package main import "fmt" @@ -15,7 +15,7 @@ func main() { fmt.Printf("Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちはせかい\n") } - +``` 输出如下: Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちはせかい diff --git a/zh/02.2.md b/zh/02.2.md index 9348534c..5adcbad1 100644 --- a/zh/02.2.md +++ b/zh/02.2.md @@ -7,46 +7,46 @@ Go语言里面定义变量有多种方式。 使用`var`关键字是Go最基本的定义变量方式,与C语言不同的是Go把变量类型放在变量名后面: - +```Go //定义一个名称为“variableName”,类型为"type"的变量 var variableName type - +``` 定义多个变量 - +```Go //定义三个类型都是“type”的变量 var vname1, vname2, vname3 type - +``` 定义变量并初始化值 - +```Go //初始化“variableName”的变量为“value”值,类型是“type” var variableName type = value - +``` 同时初始化多个变量 - +```Go /* 定义三个类型都是"type"的变量,并且分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 */ var vname1, vname2, vname3 type= v1, v2, v3 - +``` 你是不是觉得上面这样的定义有点繁琐?没关系,因为Go语言的设计者也发现了,有一种写法可以让它变得简单一点。我们可以直接忽略类型声明,那么上面的代码变成这样了: - +```Go /* 定义三个变量,它们分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 然后Go会根据其相应值的类型来帮你初始化它们 */ var vname1, vname2, vname3 = v1, v2, v3 - +``` 你觉得上面的还是有些繁琐?好吧,我也觉得。让我们继续简化: - +```Go /* 定义三个变量,它们分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 编译器会根据初始化的值自动推导出相应的类型 */ vname1, vname2, vname3 := v1, v2, v3 - +``` 现在是不是看上去非常简洁了?`:=`这个符号直接取代了`var`和`type`,这种形式叫做简短声明。不过它有一个限制,那就是它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用`var`方式来定义全局变量。 `_`(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。在这个例子中,我们将值`35`赋予`b`,并同时丢弃`34`: @@ -54,30 +54,30 @@ Go语言里面定义变量有多种方式。 _, b := 34, 35 Go对于已声明但未使用的变量会在编译阶段报错,比如下面的代码就会产生一个错误:声明了`i`但未使用。 - +```Go package main func main() { var i int } - +``` ## 常量 所谓常量,也就是在程序编译阶段就确定下来的值,而程序在运行时无法改变该值。在Go程序中,常量可定义为数值、布尔值或字符串等类型。 它的语法如下: - +```Go const constantName = value //如果需要,也可以明确指定常量的类型: const Pi float32 = 3.1415926 - +``` 下面是一些常量声明的例子: - +```Go const Pi = 3.1415926 const i = 10000 const MaxThread = 10 const prefix = "astaxie_" - +``` Go 常量和一般程序语言不同的是,可以指定相当多的小数位数(例如200位), 若指定給float32自动缩短为32bit,指定给float64自动缩短为64bit,详情参考[链接](http://golang.org/ref/spec#Constants) @@ -86,7 +86,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 ### Boolean 在Go中,布尔值的类型为`bool`,值是`true`或`false`,默认为`false`。 - +```Go //示例代码 var isActive bool // 全局变量声明 var enabled, disabled = true, false // 忽略类型的声明 @@ -95,7 +95,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 valid := false // 简短声明 available = true // 赋值操作 } - +``` ### 数值类型 @@ -116,16 +116,16 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 浮点数的类型有`float32`和`float64`两种(没有`float`类型),默认是`float64`。 这就是全部吗?No!Go还支持复数。它的默认类型是`complex128`(64位实数+64位虚数)。如果需要小一些的,也有`complex64`(32位实数+32位虚数)。复数的形式为`RE + IMi`,其中`RE`是实数部分,`IM`是虚数部分,而最后的`i`是虚数单位。下面是一个使用复数的例子: - +```Go var c complex64 = 5+5i //output: (5+5i) fmt.Printf("Value is: %v", c) - +``` ### 字符串 我们在上一节中讲过,Go中的字符串都是采用`UTF-8`字符集编码。字符串是用一对双引号(`""`)或反引号(`` ` `` `` ` ``)括起来定义,它的类型是`string`。 - +```Go //示例代码 var frenchHello string // 声明变量为字符串的一般方法 var emptyString string = "" // 声明了一个字符串变量,初始化为空字符串 @@ -134,35 +134,35 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 japaneseHello := "Konichiwa" // 同上 frenchHello = "Bonjour" // 常规赋值 } - +``` 在Go中字符串是不可变的,例如下面的代码编译时会报错:cannot assign to s[0] - +```Go var s string = "hello" s[0] = 'c' - +``` 但如果真的想要修改怎么办呢?下面的代码可以实现: - +```Go s := "hello" c := []byte(s) // 将字符串 s 转换为 []byte 类型 c[0] = 'c' s2 := string(c) // 再转换回 string 类型 fmt.Printf("%s\n", s2) - +``` Go中可以使用`+`操作符来连接两个字符串: - +```Go s := "hello," m := " world" a := s + m fmt.Printf("%s\n", a) - +``` 修改字符串也可写为: - +```Go s := "hello" s = "c" + s[1:] // 字符串虽不能更改,但可进行切片操作 fmt.Printf("%s\n", s) - +``` 如果要声明一个多行的字符串怎么办?可以通过`` ` ``来声明: m := `hello @@ -175,12 +175,12 @@ Go中可以使用`+`操作符来连接两个字符串: ### 错误类型 Go内置有一个`error`类型,专门用来处理错误信息,Go的`package`里面还专门有一个包`errors`来处理错误: - +```Go err := errors.New("emit macho dwarf: elf header corrupted") if err != nil { fmt.Print(err) } - +``` ### Go数据底层的存储 下面这张图来源于[Russ Cox Blog](http://research.swtch.com/)中一篇介绍[Go数据结构](http://research.swtch.com/godata)的文章,大家可以看到这些基础类型底层都是分配了一块内存,然后存储了相应的值。 @@ -196,7 +196,7 @@ Go内置有一个`error`类型,专门用来处理错误信息,Go的`package` 在Go语言中,同时声明多个常量、变量,或者导入多个包时,可采用分组的方式进行声明。 例如下面的代码: - +```Go import "fmt" import "os" @@ -207,9 +207,9 @@ Go内置有一个`error`类型,专门用来处理错误信息,Go的`package` var i int var pi float32 var prefix string - +``` 可以分组写成如下形式: - +```Go import( "fmt" "os" @@ -226,10 +226,11 @@ Go内置有一个`error`类型,专门用来处理错误信息,Go的`package` pi float32 prefix string ) - +``` ### iota枚举 Go里面有一个关键字`iota`,这个关键字用来声明`enum`的时候采用,它默认开始值是0,const中每增加一行加1: +```Go const( x = iota // x == 0 @@ -251,7 +252,7 @@ Go里面有一个关键字`iota`,这个关键字用来声明`enum`的时候采 d,e,f = iota,iota,iota //d=3,e=3,f=3 g //g = 4 ) - +``` >除非被显式设置为其它值或`iota`,每个`const`分组的第一个常量被默认设置为它的0值,第二及后续的常量被默认设置为它前面那个常量的值,如果前面那个常量的值是`iota`,则它也被设置为`iota`。 ### Go程序设计的一些规则 @@ -263,35 +264,37 @@ Go之所以会那么简洁,是因为它有一些默认的行为: ### array `array`就是数组,它的定义方式如下: - +```Go var arr [n]type - +``` 在`[n]type`中,`n`表示数组的长度,`type`表示存储元素的类型。对数组的操作和其它语言类似,都是通过`[]`来进行读取或赋值: - +```Go var arr [10]int // 声明了一个int类型的数组 arr[0] = 42 // 数组下标是从0开始的 arr[1] = 13 // 赋值操作 fmt.Printf("The first element is %d\n", arr[0]) // 获取数据,返回42 fmt.Printf("The last element is %d\n", arr[9]) //返回未赋值的最后一个元素,默认返回0 - +``` 由于长度也是数组类型的一部分,因此`[3]int`与`[4]int`是不同的类型,数组也就不能改变长度。数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果要使用指针,那么就需要用到后面介绍的`slice`类型了。 数组可以使用另一种`:=`来声明 +```Go a := [3]int{1, 2, 3} // 声明了一个长度为3的int数组 b := [10]int{1, 2, 3} // 声明了一个长度为10的int数组,其中前三个元素初始化为1、2、3,其它默认为0 c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度 - +``` 也许你会说,我想数组里面的值还是数组,能实现吗?当然咯,Go支持嵌套数组,即多维数组。比如下面的代码就声明了一个二维数组: +```Go // 声明了一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素 doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} // 上面的声明可以简化,直接忽略内部的类型 easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} - +``` 数组的分配如下所示: ![](images/2.2.array.png?raw=true) @@ -304,16 +307,18 @@ Go之所以会那么简洁,是因为它有一些默认的行为: 在很多应用场景中,数组并不能满足我们的需求。在初始定义数组时,我们并不知道需要多大的数组,因此我们就需要“动态数组”。在Go里面这种数据结构叫`slice` `slice`并不是真正意义上的动态数组,而是一个引用类型。`slice`总是指向一个底层`array`,`slice`的声明也可以像`array`一样,只是不需要长度。 +```Go // 和声明array一样,只是少了长度 var fslice []int - +``` 接下来我们可以声明一个`slice`,并初始化数据,如下所示: +```Go slice := []byte {'a', 'b', 'c', 'd'} - +``` `slice`可以从一个数组或一个已经存在的`slice`中再次声明。`slice`通过`array[i:j]`来获取,其中`i`是数组的开始位置,`j`是结束位置,但不包含`array[j]`,它的长度是`j-i`。 - +```Go // 声明一个含有10个元素元素类型为byte的数组 var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} @@ -327,7 +332,7 @@ Go之所以会那么简洁,是因为它有一些默认的行为: // b是数组ar的另一个slice b = ar[3:5] // b的元素是:ar[3]和ar[4] - +``` >注意`slice`和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用`...`自动计算长度,而声明`slice`时,方括号内没有任何字符。 它们的数据结构如下所示 @@ -343,6 +348,7 @@ slice有一些简便的操作 - 如果从一个数组里面直接获取`slice`,可以这样`ar[:]`,因为默认第一个序列是0,第二个是数组的长度,即等价于`ar[0:len(ar)]` 下面这个例子展示了更多关于`slice`的操作: +```Go // 声明一个数组 var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} @@ -360,17 +366,18 @@ slice有一些简便的操作 bSlice = aSlice[:3] // bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是含有: d,e,f bSlice = aSlice[0:5] // 对slice的slice可以在cap范围内扩展,此时bSlice包含:d,e,f,g,h bSlice = aSlice[:] // bSlice包含所有aSlice的元素: d,e,f,g - +``` `slice`是引用类型,所以当引用改变其中元素的值时,其它的所有引用都会改变该值,例如上面的`aSlice`和`bSlice`,如果修改了`aSlice`中元素的值,那么`bSlice`相对应的值也会改变。 从概念上面来说`slice`像一个结构体,这个结构体包含了三个元素: - 一个指针,指向数组中`slice`指定的开始位置 - 长度,即`slice`的长度 - 最大长度,也就是`slice`开始位置到数组的最后位置的长度 +```Go Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} Slice_a := Array_a[2:5] - +``` 上面代码的真正存储结构如下图所示 ![](images/2.2.slice2.png?raw=true) @@ -388,10 +395,11 @@ slice有一些简便的操作 但当`slice`中没有剩余空间(即`(cap-len) == 0`)时,此时将动态分配新的数组空间。返回的`slice`数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的`slice`则不受影响。 从Go1.2开始slice支持了三个参数的slice,之前我们一直采用这种方式在slice或者array基础上来获取一个slice +```Go var array [10]int slice := array[2:4] - +``` 这个例子里面slice的容量是8,新版本里面可以指定这个容量 slice = array[2:4:7] @@ -405,6 +413,7 @@ slice有一些简便的操作 `map`也就是Python中字典的概念,它的格式为`map[keyType]valueType` 我们看下面的代码,`map`的读取和设置也类似`slice`一样,通过`key`来操作,只是`slice`的`index`只能是`int`类型,而`map`多了很多类型,可以是`int`,可以是`string`及所有完全定义了`==`与`!=`操作的类型。 +```Go // 声明一个key是字符串,值为int的字典,这种方式的声明需要在使用之前使用make初始化 var numbers map[string]int @@ -429,6 +438,7 @@ slice有一些简便的操作 `map`的初始化可以通过`key:val`的方式初始化值,同时`map`内置有判断是否存在`key`的方式 通过`delete`删除`map`的元素: +```Go // 初始化一个字典 rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 } @@ -442,15 +452,16 @@ slice有一些简便的操作 delete(rating, "C") // 删除key为C的元素 - +``` 上面说过了,`map`也是一种引用类型,如果两个`map`同时指向一个底层,那么一个改变,另一个也相应的改变: +```Go m := make(map[string]string) m["Hello"] = "Bonjour" m1 := m m1["Hello"] = "Salut" // 现在m["hello"]的值已经是Salut了 - +``` ### make、new操作 `make`用于内建类型(`map`、`slice` 和`channel`)的内存分配。`new`用于各种类型的内存分配。 @@ -473,6 +484,7 @@ slice有一些简便的操作 ## 零值 关于“零值”,所指并非是空值,而是一种“变量未填充前”的默认值,通常为0。 此处罗列 部分类型 的 “零值” +```Go int 0 int8 0 @@ -486,6 +498,7 @@ slice有一些简便的操作 bool false string "" +``` ## links * [目录]() * 上一章: [你好,Go](<02.1.md>) From 1bb0deab32f9c3b3514d831ffe33115c8edef6c4 Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sat, 10 Dec 2016 18:02:50 +0800 Subject: [PATCH 23/32] Add syntax highlighting --- zh/02.2.md | 24 ++++++++++++++ zh/02.3.md | 95 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 31 deletions(-) diff --git a/zh/02.2.md b/zh/02.2.md index 5adcbad1..b2657426 100644 --- a/zh/02.2.md +++ b/zh/02.2.md @@ -8,21 +8,25 @@ Go语言里面定义变量有多种方式。 使用`var`关键字是Go最基本的定义变量方式,与C语言不同的是Go把变量类型放在变量名后面: ```Go + //定义一个名称为“variableName”,类型为"type"的变量 var variableName type ``` 定义多个变量 ```Go + //定义三个类型都是“type”的变量 var vname1, vname2, vname3 type ``` 定义变量并初始化值 ```Go + //初始化“variableName”的变量为“value”值,类型是“type” var variableName type = value ``` 同时初始化多个变量 ```Go + /* 定义三个类型都是"type"的变量,并且分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 @@ -31,6 +35,7 @@ Go语言里面定义变量有多种方式。 ``` 你是不是觉得上面这样的定义有点繁琐?没关系,因为Go语言的设计者也发现了,有一种写法可以让它变得简单一点。我们可以直接忽略类型声明,那么上面的代码变成这样了: ```Go + /* 定义三个变量,它们分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 @@ -40,6 +45,7 @@ Go语言里面定义变量有多种方式。 ``` 你觉得上面的还是有些繁琐?好吧,我也觉得。让我们继续简化: ```Go + /* 定义三个变量,它们分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 @@ -55,6 +61,7 @@ Go语言里面定义变量有多种方式。 Go对于已声明但未使用的变量会在编译阶段报错,比如下面的代码就会产生一个错误:声明了`i`但未使用。 ```Go + package main func main() { @@ -67,12 +74,14 @@ Go对于已声明但未使用的变量会在编译阶段报错,比如下面的 它的语法如下: ```Go + const constantName = value //如果需要,也可以明确指定常量的类型: const Pi float32 = 3.1415926 ``` 下面是一些常量声明的例子: ```Go + const Pi = 3.1415926 const i = 10000 const MaxThread = 10 @@ -87,6 +96,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 在Go中,布尔值的类型为`bool`,值是`true`或`false`,默认为`false`。 ```Go + //示例代码 var isActive bool // 全局变量声明 var enabled, disabled = true, false // 忽略类型的声明 @@ -117,6 +127,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 这就是全部吗?No!Go还支持复数。它的默认类型是`complex128`(64位实数+64位虚数)。如果需要小一些的,也有`complex64`(32位实数+32位虚数)。复数的形式为`RE + IMi`,其中`RE`是实数部分,`IM`是虚数部分,而最后的`i`是虚数单位。下面是一个使用复数的例子: ```Go + var c complex64 = 5+5i //output: (5+5i) fmt.Printf("Value is: %v", c) @@ -126,6 +137,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 我们在上一节中讲过,Go中的字符串都是采用`UTF-8`字符集编码。字符串是用一对双引号(`""`)或反引号(`` ` `` `` ` ``)括起来定义,它的类型是`string`。 ```Go + //示例代码 var frenchHello string // 声明变量为字符串的一般方法 var emptyString string = "" // 声明了一个字符串变量,初始化为空字符串 @@ -137,12 +149,14 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 ``` 在Go中字符串是不可变的,例如下面的代码编译时会报错:cannot assign to s[0] ```Go + var s string = "hello" s[0] = 'c' ``` 但如果真的想要修改怎么办呢?下面的代码可以实现: ```Go + s := "hello" c := []byte(s) // 将字符串 s 转换为 []byte 类型 c[0] = 'c' @@ -152,6 +166,7 @@ Go 常量和一般程序语言不同的是,可以指定相当多的小数位 Go中可以使用`+`操作符来连接两个字符串: ```Go + s := "hello," m := " world" a := s + m @@ -159,6 +174,7 @@ Go中可以使用`+`操作符来连接两个字符串: ``` 修改字符串也可写为: ```Go + s := "hello" s = "c" + s[1:] // 字符串虽不能更改,但可进行切片操作 fmt.Printf("%s\n", s) @@ -176,6 +192,7 @@ Go中可以使用`+`操作符来连接两个字符串: ### 错误类型 Go内置有一个`error`类型,专门用来处理错误信息,Go的`package`里面还专门有一个包`errors`来处理错误: ```Go + err := errors.New("emit macho dwarf: elf header corrupted") if err != nil { fmt.Print(err) @@ -197,6 +214,7 @@ Go内置有一个`error`类型,专门用来处理错误信息,Go的`package` 例如下面的代码: ```Go + import "fmt" import "os" @@ -210,6 +228,7 @@ Go内置有一个`error`类型,专门用来处理错误信息,Go的`package` ``` 可以分组写成如下形式: ```Go + import( "fmt" "os" @@ -265,10 +284,12 @@ Go之所以会那么简洁,是因为它有一些默认的行为: ### array `array`就是数组,它的定义方式如下: ```Go + var arr [n]type ``` 在`[n]type`中,`n`表示数组的长度,`type`表示存储元素的类型。对数组的操作和其它语言类似,都是通过`[]`来进行读取或赋值: ```Go + var arr [10]int // 声明了一个int类型的数组 arr[0] = 42 // 数组下标是从0开始的 arr[1] = 13 // 赋值操作 @@ -319,6 +340,7 @@ Go之所以会那么简洁,是因为它有一些默认的行为: ``` `slice`可以从一个数组或一个已经存在的`slice`中再次声明。`slice`通过`array[i:j]`来获取,其中`i`是数组的开始位置,`j`是结束位置,但不包含`array[j]`,它的长度是`j-i`。 ```Go + // 声明一个含有10个元素元素类型为byte的数组 var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} @@ -425,6 +447,7 @@ slice有一些简便的操作 fmt.Println("第三个数字是: ", numbers["three"]) // 读取数据 // 打印出来如:第三个数字是: 3 +``` 这个`map`就像我们平常看到的表格一样,左边列是`key`,右边列是值 @@ -438,6 +461,7 @@ slice有一些简便的操作 `map`的初始化可以通过`key:val`的方式初始化值,同时`map`内置有判断是否存在`key`的方式 通过`delete`删除`map`的元素: + ```Go // 初始化一个字典 diff --git a/zh/02.3.md b/zh/02.3.md index 71189b59..a3348656 100644 --- a/zh/02.3.md +++ b/zh/02.3.md @@ -6,6 +6,7 @@ `if`也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事。 Go里面`if`条件判断语句中不需要括号,如下代码所示 +```Go if x > 10 { fmt.Println("x is greater than 10") @@ -14,6 +15,7 @@ Go里面`if`条件判断语句中不需要括号,如下代码所示 } Go的`if`还有一个强大的地方就是条件判断语句里面允许声明一个变量,这个变量的作用域只能在该条件逻辑块内,其他地方就不起作用了,如下所示 +```Go // 计算获取值x,然后根据x返回的大小,判断是否大于10。 if x := computedValue(); x > 10 { @@ -24,8 +26,9 @@ Go的`if`还有一个强大的地方就是条件判断语句里面允许声明 //这个地方如果这样调用就编译出错了,因为x是条件里面的变量 fmt.Println(x) - +``` 多个条件的时候如下所示: +```Go if integer == 3 { fmt.Println("The integer is equal to 3") @@ -34,10 +37,11 @@ Go的`if`还有一个强大的地方就是条件判断语句里面允许声明 } else { fmt.Println("The integer is greater than 3") } - +``` ### goto Go有`goto`语句——请明智地使用它。用`goto`跳转到必须在当前函数内定义的标签。例如假设这样一个循环: +```Go func myFunc() { i := 0 @@ -46,19 +50,21 @@ Go有`goto`语句——请明智地使用它。用`goto`跳转到必须在当前 i++ goto Here //跳转到Here去 } - +``` >标签名是大小写敏感的。 ### for Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读取数据,又可以当作`while`来控制逻辑,还能迭代操作。它的语法如下: +```Go for expression1; expression2; expression3 { //... } - +``` `expression1`、`expression2`和`expression3`都是表达式,其中`expression1`和`expression3`是变量声明或者函数调用返回值之类的,`expression2`是用来条件判断,`expression1`在循环开始之前调用,`expression3`在每轮循环结束之时调用。 一个例子比上面讲那么多更有用,那么我们看看下面的例子吧: +```Go package main import "fmt" @@ -71,25 +77,28 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 fmt.Println("sum is equal to ", sum) } // 输出:sum is equal to 45 - +``` 有些时候需要进行多个赋值操作,由于Go里面没有`,`操作符,那么可以使用平行赋值`i, j = i+1, j-1` 有些时候如果我们忽略`expression1`和`expression3`: +```Go sum := 1 for ; sum < 1000; { sum += sum } - +``` 其中`;`也可以省略,那么就变成如下的代码了,是不是似曾相识?对,这就是`while`的功能。 +```Go sum := 1 for sum < 1000 { sum += sum } - +``` 在循环里面有两个关键操作`break`和`continue` ,`break`操作是跳出当前循环,`continue`是跳过本次循环。当嵌套过深的时候,`break`可以配合标签使用,即跳转至标签所指定的位置,详细参考如下例子: +```Go for index := 10; index>0; index-- { if index == 5{ @@ -99,26 +108,29 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 } // break打印出来10、9、8、7、6 // continue打印出来10、9、8、7、6、4、3、2、1 - +``` `break`和`continue`还可以跟着标号,用来跳到多重循环中的外层循环 `for`配合`range`可以用于读取`slice`和`map`的数据: +```Go for k,v:=range map { fmt.Println("map's key:",k) fmt.Println("map's val:",v) } - +``` 由于 Go 支持 “多值返回”, 而对于“声明而未被调用”的变量, 编译器会报错, 在这种情况下, 可以使用`_`来丢弃不需要的返回值 例如 +```Go for _, v := range map{ fmt.Println("map's val:", v) } - +``` ### switch 有些时候你需要写很多的`if-else`来实现一些逻辑处理,这个时候代码看上去就很丑很冗长,而且也不易于以后的维护,这个时候`switch`就能很好的解决这个问题。它的语法如下 +```Go switch sExpr { case expr1: @@ -130,8 +142,9 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 default: other code } - +``` `sExpr`和`expr1`、`expr2`、`expr3`的类型必须一致。Go的`switch`非常灵活,表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项;而如果`switch`没有表达式,它会匹配`true`。 +```Go i := 10 switch i { @@ -144,8 +157,9 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 default: fmt.Println("All I know is that i is an integer") } - +``` 在第5行中,我们把很多值聚合在了一个`case`里面,同时,Go里面`switch`默认相当于每个`case`最后带有`break`,匹配成功后不会自动向下执行其他case,而是跳出整个`switch`, 但是可以使用`fallthrough`强制执行后面的case代码。 +```Go integer := 6 switch integer { @@ -167,24 +181,26 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 default: fmt.Println("default case") } - +``` 上面的程序将输出 +```Go The integer was <= 6 The integer was <= 7 The integer was <= 8 default case - +``` ## 函数 函数是Go里面的核心设计,它通过关键字`func`来声明,它的格式如下: +```Go func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { //这里是处理逻辑代码 //返回多个值 return value1, value2 } - +``` 上面的代码我们看出 - 关键字`func`用来声明一个函数`funcName` @@ -196,6 +212,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 - 如果有返回值, 那么必须在函数的外层添加return语句 下面我们来看一个实际应用函数的例子(用来计算Max值) +```Go package main import "fmt" @@ -220,13 +237,14 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz) fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) // 也可在这直接调用它 } - +``` 上面这个里面我们可以看到`max`函数有两个参数,它们的类型都是`int`,那么第一个变量的类型可以省略(即 a,b int,而非 a int, b int),默认为离它最近的类型,同理多于2个同类型的变量或者返回值。同时我们注意到它的返回值就是一个类型,这个就是省略写法。 ### 多个返回值 Go语言比C更先进的特性,其中一点就是函数能够返回多个值。 我们直接上代码看例子 +```Go package main import "fmt" @@ -245,29 +263,34 @@ Go语言比C更先进的特性,其中一点就是函数能够返回多个值 fmt.Printf("%d + %d = %d\n", x, y, xPLUSy) fmt.Printf("%d * %d = %d\n", x, y, xTIMESy) } - +``` 上面的例子我们可以看到直接返回了两个参数,当然我们也可以命名返回参数的变量,这个例子里面只是用了两个类型,我们也可以改成如下这样的定义,然后返回的时候不用带上变量名,因为直接在函数里面初始化了。但如果你的函数是导出的(首字母大写),官方建议:最好命名返回值,因为不命名返回值,虽然使得代码更加简洁了,但是会造成生成的文档可读性差。 +```Go func SumAndProduct(A, B int) (add int, Multiplied int) { add = A+B Multiplied = A*B return } - +``` ### 变参 Go函数支持变参。接受变参的函数是有着不定数量的参数的。为了做到这点,首先需要定义函数使其接受变参: +```Go func myfunc(arg ...int) {} +``` `arg ...int`告诉Go这个函数接受不定数量的参数。注意,这些参数的类型全部是`int`。在函数体中,变量`arg`是一个`int`的`slice`: +```Go for _, n := range arg { fmt.Printf("And the number is: %d\n", n) } - +``` ### 传值与传指针 当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。 为了验证我们上面的说法,我们来看一个例子 +```Go package main import "fmt" @@ -288,7 +311,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 fmt.Println("x+1 = ", x1) // 应该输出"x+1 = 4" fmt.Println("x = ", x) // 应该输出"x = 3" } - +``` 看到了吗?虽然我们调用了`add1`函数,并且在`add1`中执行`a = a+1`操作,但是上面例子中`x`变量的值没有发生变化 理由很简单:因为当我们调用`add1`的时候,`add1`接收的参数其实是`x`的copy,而不是`x`本身。 @@ -296,6 +319,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 那你也许会问了,如果真的需要传这个`x`本身,该怎么办呢? 这就牵扯到了所谓的指针。我们知道,变量在内存中是存放于一定地址上的,修改变量实际是修改变量地址处的内存。只有`add1`函数知道`x`变量所在的地址,才能修改`x`变量的值。所以我们需要将`x`所在地址`&x`传入函数,并将函数的参数的类型由`int`改为`*int`,即改为指针类型,才能在函数中修改`x`变量的值。此时参数仍然是按copy传递的,只是copy的是一个指针。请看下面的例子 +```Go package main import "fmt" @@ -316,7 +340,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 fmt.Println("x+1 = ", x1) // 应该输出 "x+1 = 4" fmt.Println("x = ", x) // 应该输出 "x = 4" } - +``` 这样,我们就达到了修改`x`的目的。那么到底传指针有什么好处呢? - 传指针使得多个函数能操作同一个对象。 @@ -325,6 +349,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 ### defer Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题。如下代码所示,我们一般写打开一个资源是这样操作的: +```Go func ReadWrite() bool { file.Open("file") @@ -342,8 +367,9 @@ Go语言中有种不错的设计,即延迟(defer)语句,你可以在函 file.Close() return true } - +``` 我们看到上面有很多重复的代码,Go的`defer`有效解决了这个问题。使用它后,不但代码量减少了很多,而且程序变得更优雅。在`defer`后指定的函数会在函数退出前调用。 +```Go func ReadWrite() bool { file.Open("file") @@ -356,13 +382,14 @@ Go语言中有种不错的设计,即延迟(defer)语句,你可以在函 } return true } - +``` 如果有很多调用`defer`,那么`defer`是采用后进先出模式,所以如下代码会输出`4 3 2 1 0` +```Go for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) } - +``` ### 函数作为值、类型 在Go中函数也是一种变量,我们可以通过`type`来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型 @@ -370,6 +397,7 @@ Go语言中有种不错的设计,即延迟(defer)语句,你可以在函 type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...]) 函数作为类型到底有什么好处呢?那就是可以把这个类型的函数当做值来传递,请看下面的例子 +```Go package main import "fmt" @@ -410,7 +438,7 @@ Go语言中有种不错的设计,即延迟(defer)语句,你可以在函 even := filter(slice, isEven) // 函数当做值来传递了 fmt.Println("Even elements of slice are: ", even) } - +``` 函数当做值和类型在我们写一些通用接口的时候非常有用,通过上面例子我们看到`testInt`这个类型是一个函数类型,然后两个`filter`函数的参数和返回值与`testInt`类型是一样的,但是我们可以实现很多种的逻辑,这样使得我们的程序变得非常的灵活。 ### Panic和Recover @@ -424,6 +452,7 @@ Recover >是一个内建的函数,可以让进入令人恐慌的流程中的`goroutine`恢复过来。`recover`仅在延迟函数中有效。在正常的执行过程中,调用`recover`会返回`nil`,并且没有其它任何效果。如果当前的`goroutine`陷入恐慌,调用`recover`可以捕获到`panic`的输入值,并且恢复正常的执行。 下面这个函数演示了如何在过程中使用`panic` +```Go var user = os.Getenv("USER") @@ -432,8 +461,9 @@ Recover panic("no value for $USER") } } - +``` 下面这个函数检查作为其参数的函数在执行时是否会产生`panic`: +```Go func throwsPanic(f func()) (b bool) { defer func() { @@ -444,7 +474,7 @@ Recover f() //执行函数f,如果f中出现了panic,那么就可以恢复回来 return } - +``` ### `main`函数和`init`函数 Go里面有两个保留的函数:`init`函数(能够应用于所有的`package`)和`main`函数(只能应用于`package main`)。这两个函数在定义时不能有任何的参数和返回值。虽然一个`package`里面可以写任意多个`init`函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个`package`中每个文件只写一个`init`函数。 @@ -459,15 +489,17 @@ Go程序会自动调用`init()`和`main()`,所以你不需要在任何地方 ### import 我们在写Go代码的时候经常用到import这个命令用来导入包文件,而我们经常看到的方式参考如下: +```Go import( "fmt" ) - +``` 然后我们代码里面可以通过如下的方式调用 +```Go fmt.Println("hello world") - +``` 上面这个fmt是Go语言的标准库,其实是去`GOROOT`环境变量指定目录下去加载该模块,当然Go的import还支持如下两种方式来加载自己写的模块: 1. 相对路径 @@ -505,12 +537,13 @@ Go程序会自动调用`init()`和`main()`,所以你不需要在任何地方 3. _操作 这个操作经常是让很多人费解的一个操作符,请看下面这个import - +```Go + import ( "database/sql" _ "github.com/ziutek/mymysql/godrv" ) - +``` _操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。 From e476a6e0d0a9151341ba2585811f408655d7c8d6 Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sat, 10 Dec 2016 18:08:05 +0800 Subject: [PATCH 24/32] Add syntax highlighting --- zh/02.3.md | 2 +- zh/02.4.md | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/zh/02.3.md b/zh/02.3.md index a3348656..f5588d8a 100644 --- a/zh/02.3.md +++ b/zh/02.3.md @@ -13,7 +13,7 @@ Go里面`if`条件判断语句中不需要括号,如下代码所示 } else { fmt.Println("x is less than 10") } - +``` Go的`if`还有一个强大的地方就是条件判断语句里面允许声明一个变量,这个变量的作用域只能在该条件逻辑块内,其他地方就不起作用了,如下所示 ```Go diff --git a/zh/02.4.md b/zh/02.4.md index 5cdbad44..fd7e9c25 100644 --- a/zh/02.4.md +++ b/zh/02.4.md @@ -1,16 +1,19 @@ # 2.4 struct类型 ## struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器。例如,我们可以创建一个自定义类型`person`代表一个人的实体。这个实体拥有属性:姓名和年龄。这样的类型我们称之`struct`。如下代码所示: +```Go type person struct { name string age int } +``` 看到了吗?声明一个struct如此简单,上面的类型包含有两个字段 - 一个string类型的字段name,用来保存用户名称这个属性 - 一个int类型的字段age,用来保存用户年龄这个属性 如何使用struct呢?请看下面的代码 +```Go type person struct { name string @@ -22,6 +25,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 P.name = "Astaxie" // 赋值"Astaxie"给P的name属性. P.age = 25 // 赋值"25"给变量P的age属性 fmt.Printf("The person's name is %s", P.name) // 访问P的name属性. +``` 除了上面这种P的声明使用之外,还有另外几种声明使用方式: - 1.按照顺序提供初始化值 @@ -37,6 +41,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 P := new(person) 下面我们看一个完整的使用struct的例子 +```Go package main import "fmt" @@ -81,13 +86,14 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff) } - +``` ### struct的匿名字段 我们上面介绍了如何定义一个struct,定义的时候是字段名与其类型一一对应,实际上Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。 当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。 让我们来看一个例子,让上面说的这些更具体化 +```Go package main import "fmt" @@ -125,7 +131,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 mark.weight += 60 fmt.Println("His weight is", mark.weight) } - +``` 图例如下: ![](images/2.4.student_struct.png?raw=true) @@ -133,11 +139,13 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 图2.7 struct组合,Student组合了Human struct和string基本类型 我们看到Student访问属性age和name的时候,就像访问自己所有用的字段一样,对,匿名字段就是这样,能够实现字段的继承。是不是很酷啊?还有比这个更酷的呢,那就是student还能访问Human这个字段作为字段名。请看下面的代码,是不是更酷了。 +```Go mark.Human = Human{"Marcus", 55, 220} mark.Human.age -= 1 - +``` 通过匿名访问和修改字段相当的有用,但是不仅仅是struct字段哦,所有的内置类型和自定义类型都是可以作为匿名字段的。请看下面的例子 +```Go package main import "fmt" @@ -175,7 +183,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 jane.int = 3 fmt.Println("Her preferred number is", jane.int) } - +``` 从上面例子我们看出来struct不仅仅能够将struct作为匿名字段、自定义类型、内置类型都可以作为匿名字段,而且可以在相应的字段上面进行函数操作(如例子中的append)。 这里有一个问题:如果human里面有一个字段叫做phone,而student也有一个字段叫做phone,那么该怎么办呢? @@ -183,6 +191,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 Go里面很简单的解决了这个问题,最外层的优先访问,也就是当你通过`student.phone`访问的时候,是访问student里面的字段,而不是human里面的字段。 这样就允许我们去重载通过匿名字段继承的一些字段,当然如果我们想访问重载后对应匿名类型里面的字段,可以通过匿名字段名来访问。请看下面的例子 +```Go package main import "fmt" @@ -205,7 +214,7 @@ Go里面很简单的解决了这个问题,最外层的优先访问,也就是 // 如果我们要访问Human的phone字段 fmt.Println("Bob's personal phone is:", Bob.Human.phone) } - +``` ## links * [目录]() From b3073141cb201ec5c3a4edc2218f9f93bd694a57 Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sat, 10 Dec 2016 19:22:17 +0800 Subject: [PATCH 25/32] Add syntax highlighting --- zh/02.1.md | 1 + zh/02.5.md | 21 ++++++++++++++------- zh/02.6.md | 46 ++++++++++++++++++++++++++++++++-------------- zh/02.7.md | 34 ++++++++++++++++++++++------------ zh/02.8.md | 3 ++- 5 files changed, 71 insertions(+), 34 deletions(-) diff --git a/zh/02.1.md b/zh/02.1.md index a5a1a7b9..18d770de 100644 --- a/zh/02.1.md +++ b/zh/02.1.md @@ -8,6 +8,7 @@ 准备好了吗?Let's Go! ```Go + package main import "fmt" diff --git a/zh/02.5.md b/zh/02.5.md index 63d22239..59b091f7 100644 --- a/zh/02.5.md +++ b/zh/02.5.md @@ -3,6 +3,7 @@ ## method 现在假设有这么一个场景,你定义了一个struct叫做长方形,你现在想要计算他的面积,那么按照我们一般的思路应该会用下面的方式来实现 +```Go package main import "fmt" @@ -21,7 +22,7 @@ fmt.Println("Area of r1 is: ", area(r1)) fmt.Println("Area of r2 is: ", area(r2)) } - +``` 这段代码可以计算出来长方形的面积,但是area()不是作为Rectangle的方法实现的(类似面向对象里面的方法),而是将Rectangle的对象(如r1,r2)作为参数传入函数计算面积的。 这样实现当然没有问题咯,但是当需要增加圆形、正方形、五边形甚至其它多边形的时候,你想计算他们的面积的时候怎么办啊?那就只能增加新的函数咯,但是函数名你就必须要跟着换了,变成`area_rectangle, area_circle, area_triangle...` @@ -49,6 +50,7 @@ method的语法如下: func (r ReceiverType) funcName(parameters) (results) 下面我们用最开始的例子用method来实现: +```Go package main import ( @@ -85,7 +87,7 @@ method的语法如下: fmt.Println("Area of c2 is: ", c2.area()) } - +``` 在使用method的时候重要注意几点 @@ -104,10 +106,12 @@ method的语法如下: >值得说明的一点是,图示中method用虚线标出,意思是此处方法的Receiver是以值传递,而非引用传递,是的,Receiver还可以是指针, 两者的差别在于, 指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。后文对此会有详细论述。 那是不是method只能作用在struct上面呢?当然不是咯,他可以定义在任何你自定义的类型、内置类型、struct等各种类型上面。这里你是不是有点迷糊了,什么叫自定义类型,自定义类型不就是struct嘛,不是这样的哦,struct只是自定义类型里面一种比较特殊的类型而已,还有其他自定义类型申明,可以通过如下这样的申明来实现。 +```Go type typeName typeLiteral - +``` 请看下面这个申明自定义类型的代码 +```Go type ages int @@ -121,12 +125,13 @@ method的语法如下: ... "December":31, } - +``` 看到了吗?简单的很吧,这样你就可以在自己的代码里面定义有意义的类型了,实际上只是一个定义了一个别名,有点类似于c中的typedef,例如上面ages替代了int 好了,让我们回到`method` 你可以在任何的自定义类型中定义任意多的`method`,接下来让我们看一个复杂一点的例子 +```Go package main import "fmt" @@ -200,7 +205,7 @@ method的语法如下: fmt.Println("Obviously, now, the biggest one is", boxes.BiggestColor().String()) } - +``` 上面的代码通过const定义了一些常量,然后定义了一些自定义类型 - Color作为byte的别名 @@ -242,6 +247,7 @@ method的语法如下: ### method继承 前面一章我们学习了字段的继承,那么你也会发现Go的一个神奇之处,method也是可以继承的。如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method。让我们来看下面这个例子 +```Go package main import "fmt" @@ -274,9 +280,10 @@ method的语法如下: mark.SayHi() sam.SayHi() } - +``` ### method重写 上面的例子中,如果Employee想要实现自己的SayHi,怎么办?简单,和匿名字段冲突一样的道理,我们可以在Employee上面定义一个method,重写了匿名字段的方法。请看下面的例子 +```Go package main import "fmt" @@ -315,7 +322,7 @@ method的语法如下: mark.SayHi() sam.SayHi() } - +``` 上面的代码设计的是如此的美妙,让人不自觉的为Go的设计惊叹! 通过这些内容,我们可以设计出基本的面向对象的程序了,但是Go里面的面向对象是如此的简单,没有任何的私有、公有关键字,通过大小写来实现(大写开头的为公有,小写开头的为私有),方法也同样适用这个原则。 diff --git a/zh/02.6.md b/zh/02.6.md index 57b38fd0..986d4374 100644 --- a/zh/02.6.md +++ b/zh/02.6.md @@ -14,6 +14,7 @@ Go语言里面设计最精妙的应该算interface,它让面向对象,内容 上面这些方法的组合称为interface(被对象Student和Employee实现)。例如Student和Employee都实现了interface:SayHi和Sing,也就是这两个对象是该interface类型。而Employee没有实现这个interface:SayHi、Sing和BorrowMoney,因为Employee没有实现BorrowMoney这个方法。 ### interface类型 interface类型定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。详细的语法参考下面这个例子 +```Go type Human struct { name string @@ -82,7 +83,7 @@ interface类型定义了一组方法,如果某个对象实现了某个接口 Sing(song string) SpendSalary(amount float32) } - +``` 通过上面的代码我们可以知道,interface可以被任意的对象实现。我们看到上面的Men interface被Human、Student和Employee实现。同理,一个对象可以实现任意多个interface,例如上面的Student实现了Men和YoungChap两个interface。 最后,任意的类型都实现了空interface(我们这样定义:interface{}),也就是包含0个method的interface。 @@ -93,6 +94,7 @@ interface类型定义了一组方法,如果某个对象实现了某个接口 因为m能够持有这三种类型的对象,所以我们可以定义一个包含Men类型元素的slice,这个slice可以被赋予实现了Men接口的任意结构的对象,这个和我们传统意义上面的slice有所不同。 让我们来看一下下面这个例子: +```Go package main import "fmt" @@ -169,11 +171,12 @@ interface类型定义了一组方法,如果某个对象实现了某个接口 value.SayHi() } } - +``` 通过上面的代码,你会发现interface就是一组抽象方法的集合,它必须由其他非interface类型实现,而不能自我实现, Go通过interface实现了duck-typing:即"当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子"。 ### 空interface 空interface(interface{})不包含任何的method,正因为如此,所有的类型都实现了空interface。空interface对于描述起不到任何的作用(因为它不包含任何的method),但是空interface在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。 +```Go // 定义a为空接口 var a interface{} @@ -182,17 +185,20 @@ interface类型定义了一组方法,如果某个对象实现了某个接口 // a可以存储任意类型的数值 a = i a = s - +``` 一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。是不是很有用啊! ### interface函数参数 interface的变量可以持有任意实现该interface类型的对象,这给我们编写函数(包括method)提供了一些额外的思考,我们是不是可以通过定义interface参数,让函数接受各种类型的参数。 举个例子:fmt.Println是我们常用的一个函数,但是你是否注意到它可以接受任意类型的数据。打开fmt的源码文件,你会看到这样一个定义: +```Go type Stringer interface { String() string } +``` 也就是说,任何实现了String方法的类型都能作为参数被fmt.Println调用,让我们来试一试 +```Go package main import ( @@ -215,12 +221,14 @@ interface的变量可以持有任意实现该interface类型的对象,这给 Bob := Human{"Bob", 39, "000-7777-XXX"} fmt.Println("This Human is : ", Bob) } +``` 现在我们再回顾一下前面的Box示例,你会发现Color结构也定义了一个method:String。其实这也是实现了fmt.Stringer这个interface,即如果需要某个类型能被fmt包以特殊的格式输出,你就必须实现Stringer这个接口。如果没有实现这个接口,fmt将以默认的方式输出。 +```Go //实现同样的功能 fmt.Println("The biggest one is", boxes.BiggestsColor().String()) fmt.Println("The biggest one is", boxes.BiggestsColor()) - +``` 注:实现了error接口的对象(即实现了Error() string的对象),使用fmt输出时,会调用Error()方法,因此不必再定义String()方法了。 ### interface变量存储的类型 @@ -233,6 +241,7 @@ interface的变量可以持有任意实现该interface类型的对象,这给 如果element里面确实存储了T类型的数值,那么ok返回true,否则返回false。 让我们通过一个例子来更加深入的理解。 +```Go package main @@ -272,13 +281,14 @@ interface的变量可以持有任意实现该interface类型的对象,这给 } } } - +``` 是不是很简单啊,同时你是否注意到了多个if里面,还记得我前面介绍流程时讲过,if里面允许初始化变量。 也许你注意到了,我们断言的类型越多,那么if else也就越多,所以才引出了下面要介绍的switch。 - switch测试 最好的讲解就是代码例子,现在让我们重写上面的这个实现 +```Go package main @@ -319,21 +329,23 @@ interface的变量可以持有任意实现该interface类型的对象,这给 } } } - +``` 这里有一点需要强调的是:`element.(type)`语法不能在switch外的任何逻辑里面使用,如果你要在switch外面判断一个类型就使用`comma-ok`。 ### 嵌入interface Go里面真正吸引人的是它内置的逻辑语法,就像我们在学习Struct时学习的匿名字段,多么的优雅啊,那么相同的逻辑引入到interface里面,那不是更加完美了。如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式的包含了interface1里面的method。 我们可以看到源码包container/heap里面有这样的一个定义 +```Go type Interface interface { sort.Interface //嵌入字段sort.Interface Push(x interface{}) //a Push method to push elements into the heap Pop() interface{} //a Pop elements that pops elements from the heap } - +``` 我们看到sort.Interface其实就是嵌入字段,把sort.Interface的所有method给隐式的包含进来了。也就是下面三个方法: +```Go type Interface interface { // Len is the number of elements in the collection. @@ -344,49 +356,55 @@ Go里面真正吸引人的是它内置的逻辑语法,就像我们在学习Str // Swap swaps the elements with indexes i and j. Swap(i, j int) } - +``` 另一个例子就是io包下面的 io.ReadWriter ,它包含了io包下面的Reader和Writer两个interface: +```Go // io.ReadWriter type ReadWriter interface { Reader Writer } - +``` ### 反射 Go语言实现了反射,所谓反射就是能检查程序在运行时的状态。我们一般用到的包是reflect包。如何运用reflect包,官方的这篇文章详细的讲解了reflect包的实现原理,[laws of reflection](http://golang.org/doc/articles/laws_of_reflection.html) 使用reflect一般分成三步,下面简要的讲解一下:要去反射是一个类型的值(这些值都实现了空interface),首先需要把它转化成reflect对象(reflect.Type或者reflect.Value,根据不同的情况调用不同的函数)。这两种获取方式如下: +```Go t := reflect.TypeOf(i) //得到类型的元数据,通过t我们能获取类型定义里面的所有元素 v := reflect.ValueOf(i) //得到实际的值,通过v我们获取存储在里面的值,还可以去改变值 - +``` 转化为reflect对象之后我们就可以进行一些操作了,也就是将reflect对象转化成相应的值,例如 +```Go tag := t.Elem().Field(0).Tag //获取定义在struct里面的标签 name := v.Elem().Field(0).String() //获取存储在第一个字段里面的值 - +``` 获取反射值能返回相应的类型和数值 +```Go var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) fmt.Println("value:", v.Float()) - +``` 最后,反射的话,那么反射的字段必须是可修改的,我们前面学习过传值和传引用,这个里面也是一样的道理。反射的字段必须是可读写的意思是,如果下面这样写,那么会发生错误 +```Go var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.1) - +``` 如果要修改相应的值,必须这样写 +```Go var x float64 = 3.4 p := reflect.ValueOf(&x) v := p.Elem() v.SetFloat(7.1) - +``` 上面只是对反射的简单介绍,更深入的理解还需要自己在编程中不断的实践。 ## links diff --git a/zh/02.7.md b/zh/02.7.md index 7c7fc0b1..f6146e92 100644 --- a/zh/02.7.md +++ b/zh/02.7.md @@ -7,10 +7,12 @@ goroutine是Go并行设计的核心。goroutine说到底其实就是线程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。 goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过`go`关键字实现了,其实就是一个普通的函数。 +```Go go hello(a, b, c) - +``` 通过关键字go就启动了一个goroutine。我们来看一个例子 +```Go package main @@ -41,7 +43,7 @@ goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过`g // hello // world // hello - +``` 我们可以看到go关键字很方便的就实现了并发编程。 上面的多个goroutine运行在同一个进程里面,共享内存数据,不过设计上我们要遵循:不要通过共享来通信,而要通过通信来共享。 @@ -51,17 +53,20 @@ goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过`g ## channels goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢,Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比:可以通过它发送或者接收值。这些值只能是特定的类型:channel类型。定义一个channel时,也需要定义发送到channel的值的类型。注意,必须使用make 创建channel: +```Go ci := make(chan int) cs := make(chan string) cf := make(chan interface{}) - +``` channel通过操作符`<-`来接收和发送数据 +```Go ch <- v // 发送v到channel ch. v := <-ch // 从ch中接收数据,并赋值给v - +``` 我们把这些应用到我们的例子中来: +```Go package main @@ -85,18 +90,19 @@ channel通过操作符`<-`来接收和发送数据 fmt.Println(x, y, x + y) } - +``` 默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得Goroutines同步变的更加的简单,而不需要显式的lock。所谓阻塞,也就是如果读取(value := <-ch)它将会被阻塞,直到有数据接收。其次,任何发送(ch<-5)将会被阻塞,直到数据被读出。无缓冲channel是在多个goroutine之间同步很棒的工具。 ## Buffered Channels 上面我们介绍了默认的非缓存类型的channel,不过Go也允许指定channel的缓冲大小,很简单,就是channel可以存储多少元素。ch:= make(chan bool, 4),创建了可以存储4个元素的bool 型channel。在这个channel 中,前4个元素可以无阻塞的写入。当写入第5个元素时,代码将会阻塞,直到其他goroutine从channel 中读取一些元素,腾出空间。 +```Go ch := make(chan type, value) - +``` 当 value = 0 时,channel 是无缓冲阻塞读写的,当value > 0 时,channel 有缓冲、是非阻塞的,直到写满 value 个元素才阻塞写入。 我们看一下下面这个例子,你可以在自己本机测试一下,修改相应的value值 - +```Go package main @@ -111,9 +117,10 @@ channel通过操作符`<-`来接收和发送数据 } //修改为1报如下的错误: //fatal error: all goroutines are asleep - deadlock! - +``` ## Range和Close 上面这个例子中,我们需要读取两次c,这样不是很方便,Go考虑到了这一点,所以也可以通过range,像操作slice或者map一样操作缓存类型的channel,请看下面的例子 +```Go package main @@ -137,7 +144,7 @@ channel通过操作符`<-`来接收和发送数据 fmt.Println(i) } } - +``` `for i := range c`能够不断的读取channel里面的数据,直到该channel被显式的关闭。上面代码我们看到可以显式的关闭channel,生产者通过内置函数`close`关闭channel。关闭channel之后就无法再发送任何数据了,在消费方可以通过语法`v, ok := <-ch`测试channel是否被关闭。如果ok返回false,那么说明channel已经没有任何数据并且已经被关闭。 >记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它,这样容易引起panic @@ -148,6 +155,7 @@ channel通过操作符`<-`来接收和发送数据 我们上面介绍的都是只有一个channel的情况,那么如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字`select`,通过`select`可以监听channel上的数据流动。 `select`默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。 +```Go package main @@ -177,8 +185,9 @@ channel通过操作符`<-`来接收和发送数据 }() fibonacci(c, quit) } - +``` 在`select`里面还有default语法,`select`其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。 +```Go select { case i := <-c: @@ -186,9 +195,10 @@ channel通过操作符`<-`来接收和发送数据 default: // 当c阻塞的时候执行这里 } - +``` ## 超时 有时候会出现goroutine阻塞的情况,那么我们如何避免整个程序进入阻塞的情况呢?我们可以利用select来设置超时,通过如下的方式实现: +```Go func main() { c := make(chan int) @@ -207,7 +217,7 @@ channel通过操作符`<-`来接收和发送数据 }() <- o } - +``` ## runtime goroutine runtime包中有几个处理goroutine的函数: diff --git a/zh/02.8.md b/zh/02.8.md index a0ec6bb9..ca82b482 100644 --- a/zh/02.8.md +++ b/zh/02.8.md @@ -1,13 +1,14 @@ # 2.8 总结 这一章我们主要介绍了Go语言的一些语法,通过语法我们可以发现Go是多么的简单,只有二十五个关键字。让我们再来回顾一下这些关键字都是用来干什么的。 +```Go break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var - +``` - var和const参考2.2Go语言基础里面的变量和常量申明 - package和import已经有过短暂的接触 - func 用于定义函数和方法 From 6d9d76f242f82141aea8ea9de64e71107c8c2b67 Mon Sep 17 00:00:00 2001 From: vCaesar Date: Sat, 10 Dec 2016 21:22:09 +0800 Subject: [PATCH 26/32] Fmt some code examples --- zh/02.3.md | 6 ++++++ zh/02.4.md | 4 ++++ zh/02.5.md | 5 +++++ zh/02.6.md | 1 + 4 files changed, 16 insertions(+) diff --git a/zh/02.3.md b/zh/02.3.md index f5588d8a..c642b983 100644 --- a/zh/02.3.md +++ b/zh/02.3.md @@ -67,6 +67,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 ```Go package main + import "fmt" func main(){ @@ -215,6 +216,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读 ```Go package main + import "fmt" // 返回a、b中最大值. @@ -247,6 +249,7 @@ Go语言比C更先进的特性,其中一点就是函数能够返回多个值 ```Go package main + import "fmt" //返回 A+B 和 A*B @@ -293,6 +296,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 ```Go package main + import "fmt" //简单的一个函数,实现了参数+1的操作 @@ -322,6 +326,7 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。 ```Go package main + import "fmt" //简单的一个函数,实现了参数+1的操作 @@ -400,6 +405,7 @@ Go语言中有种不错的设计,即延迟(defer)语句,你可以在函 ```Go package main + import "fmt" type testInt func(int) bool // 声明了一个函数类型 diff --git a/zh/02.4.md b/zh/02.4.md index fd7e9c25..70570368 100644 --- a/zh/02.4.md +++ b/zh/02.4.md @@ -44,6 +44,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 ```Go package main + import "fmt" // 声明一个新的类型 @@ -96,6 +97,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 ```Go package main + import "fmt" type Human struct { @@ -148,6 +150,7 @@ Go语言中,也和C或者其他语言一样,我们可以声明新的类型 ```Go package main + import "fmt" type Skills []string @@ -194,6 +197,7 @@ Go里面很简单的解决了这个问题,最外层的优先访问,也就是 ```Go package main + import "fmt" type Human struct { diff --git a/zh/02.5.md b/zh/02.5.md index 59b091f7..671fc278 100644 --- a/zh/02.5.md +++ b/zh/02.5.md @@ -6,6 +6,7 @@ ```Go package main + import "fmt" type Rectangle struct { @@ -53,6 +54,7 @@ method的语法如下: ```Go package main + import ( "fmt" "math" @@ -134,6 +136,7 @@ method的语法如下: ```Go package main + import "fmt" const( @@ -250,6 +253,7 @@ method的语法如下: ```Go package main + import "fmt" type Human struct { @@ -286,6 +290,7 @@ method的语法如下: ```Go package main + import "fmt" type Human struct { diff --git a/zh/02.6.md b/zh/02.6.md index 986d4374..883d0f9a 100644 --- a/zh/02.6.md +++ b/zh/02.6.md @@ -97,6 +97,7 @@ interface类型定义了一组方法,如果某个对象实现了某个接口 ```Go package main + import "fmt" type Human struct { From 2048c18928bfeaed83a07f1a83ff559343a32024 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 18:57:16 +0100 Subject: [PATCH 27/32] fix typo --- de/02.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/de/02.2.md b/de/02.2.md index 4a640fc4..9a9d870c 100644 --- a/de/02.2.md +++ b/de/02.2.md @@ -219,7 +219,7 @@ Gruppierter Ansatz. prefix string ) -Wird innerhalb von `constant()` einer Konstanten das Schlüsselwort `iota` als Wert zugewiesen, hat sie den Wert `0`. Werden den folgenden Konstanten keinee expliziten Werte zugewiesen, wird der letzte zugeweise Wert von `iota` um 1 erhöht und und der folgenden Konstante zugewiesen. Dieses Verhalten beleuchten wir im folgenden Absatz. +Wird innerhalb von `constant()` einer Konstanten das Schlüsselwort `iota` als Wert zugewiesen, hat sie den Wert `0`. Werden den folgenden Konstanten keine expliziten Werte zugewiesen, wird der letzte zugeweise Wert von `iota` um 1 erhöht und der folgenden Konstante zugewiesen. Dieses Verhalten beleuchten wir im folgenden Absatz. ### Aufzählen mit iota From 35ea33448d8988d9d8b61429f72936581c9f9fb8 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 18:59:19 +0100 Subject: [PATCH 28/32] Fix Typo Im dem Fall -> Im Fall --- de/02.3.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/de/02.3.md b/de/02.3.md index 564031a5..be0d87ae 100644 --- a/de/02.3.md +++ b/de/02.3.md @@ -333,7 +333,7 @@ Nun können wir den Wert von `x` in der Funktion ändern. Aber warum nutzen wir ### defer -Go besitzt mit `defer` ein weiteres nützliches Schlüsselwort. Du kannst `defer` mehrmals in einer Funktion nutzen. Sie werden in umgekehrter Reihenfolge am Ende einer Funktion ausgeführt. Im dem Fall, dass Dein Programm eine Datei öffnet, muss diese erst wieder geschlossen werden, bevor Fehler zurückgeben werden können. Schauen wir uns ein paar Beispiele an. +Go besitzt mit `defer` ein weiteres nützliches Schlüsselwort. Du kannst `defer` mehrmals in einer Funktion nutzen. Sie werden in umgekehrter Reihenfolge am Ende einer Funktion ausgeführt. Im Fall, dass Dein Programm eine Datei öffnet, muss diese erst wieder geschlossen werden, bevor Fehler zurückgeben werden können. Schauen wir uns ein paar Beispiele an. func LesenSchreiben() bool { file.Open("Datei") @@ -520,4 +520,4 @@ Es gibt spezielle Operatoren beim Importieren von Paketen, die Anfänger oftmals - [Inhaltsverzeichnis](preface.md) - Vorheriger Abschnitt: [Grundlagen von Go](02.2.md) -- Nächster Abschnitt: [Struct](02.4.md) \ No newline at end of file +- Nächster Abschnitt: [Struct](02.4.md) From c2e67b927bf02cc86a64dca113c8c0002a7a7ede Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 19:00:50 +0100 Subject: [PATCH 29/32] Fix Typo --- de/02.4.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/de/02.4.md b/de/02.4.md index 98d7dc3c..592d8a6c 100644 --- a/de/02.4.md +++ b/de/02.4.md @@ -179,7 +179,7 @@ In Go können alle Datenttypen eingebettet werden. fmt.Println("Ihre bevorzugte Nummer lautet", jane.int) } -Im oberen Beispiel ist erkenntlich, dass alle Datentypen eingebettet werden und Funktion auf ihre Werte zugreifen können. +Im oberen Beispiel ist erkenntlich, dass alle Datentypen eingebettet werden und Funktionen auf ihre Werte zugreifen können. Aber es gibt noch ein kleines Problem. Was geschieht, wenn Mensch die Eigenschaft `telefon` besitzt und Student eine Eigenschaft mit dem gleichen Namen besitzt? @@ -211,4 +211,4 @@ Go nutzt einen einfachen Weg zur Unterscheidung. Um die Eigenschaft `telefon` vo - [Inhaltsverzeichnis](preface.md) - Vorheriger Abschnitt: [Kontrollstrukturen und Funktionen](02.3.md) -- Nächster Abschnitt: [Objektorientiertes Programmieren](02.5.md) \ No newline at end of file +- Nächster Abschnitt: [Objektorientiertes Programmieren](02.5.md) From 308e13405d4193e10a367a0fd25184b0740c5ee7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 19:02:19 +0100 Subject: [PATCH 30/32] Fix Typo --- de/02.5.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/de/02.5.md b/de/02.5.md index 613d52ab..745bdc25 100644 --- a/de/02.5.md +++ b/de/02.5.md @@ -1,6 +1,6 @@ # 2.5 Objektorientierte Programmierung -In den letzen beiden Abschnitten hatten wir uns mit Funktionen und Structs beschäftigt, aber hast Du jemals daran gedacht, Funktionen als Eigenschaft in einem Struct zu verwenden? In diesem Abschnitt werden ich Dir eine besondere Art von Funktionen vorstellen, die einen Reciever (engl. to recieve - empfangen) besitzen. Sie werden auch `Methoden` genannt. +In den letzen beiden Abschnitten hatten wir uns mit Funktionen und Structs beschäftigt, aber hast Du jemals daran gedacht, Funktionen als Eigenschaft in einem Struct zu verwenden? In diesem Abschnitt werde ich Dir eine besondere Art von Funktionen vorstellen, die einen Reciever (engl. to recieve - empfangen) besitzen. Sie werden auch `Methoden` genannt. ## Methoden @@ -306,4 +306,4 @@ Nun bist Du bereit, Dein eigenes, objektorientiers Programm zu schreiben. Auch M - [Inhaltsverzeichnis](preface.md) - Vorheriger Abschnitt: [Struct](02.4.md) -- Nächster Abschnitt: [Interface](02.6.md) \ No newline at end of file +- Nächster Abschnitt: [Interface](02.6.md) From a7995979155ea12be1140c5eef50330a09e97613 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 19:04:28 +0100 Subject: [PATCH 31/32] Fix Typo --- de/02.6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/de/02.6.md b/de/02.6.md index f36c2528..be3f18de 100644 --- a/de/02.6.md +++ b/de/02.6.md @@ -89,7 +89,7 @@ Zudem implementiert jeder Datentyp das leere Interface `interface{}`, da es kein ### Interface als Datentyp -Welche Arten von Werten können mit einem Interface verknüpft werden? Wen wir eine Variable vom Typ Interface definieren, dann kann jeder Datentyp, der das Interface implementiert wird, der Variable zugewiesen werden. +Welche Arten von Werten können mit einem Interface verknüpft werden? Wen wir eine Variable vom Typ Interface definieren, dann kann jeder Datentyp, der das Interface implementiert, der Variable zugewiesen werden. Es ist wie im oberen Beispiel. Erstellen wir eine Variable "m" mit dem Interface Männer, kann jeder Student, Mensch oder Mitarbeiter "m" zugewiesen werden. So könnten wir ein Slice mit dem Interface Männer jeden Datentyp hinzufügen, der ebenfalls das Interface Männer implementiert. Bedenke aber, dass sich das Verhalten von Slices ändert, wenn dies Elemente eines Interface statt eines Datentypes verwendet. From b20e61d499a8a1253293d1d5ddd232b3d31b86a7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 19:05:51 +0100 Subject: [PATCH 32/32] Fix Typo --- de/02.8.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/de/02.8.md b/de/02.8.md index 197e4d92..ad7784ba 100644 --- a/de/02.8.md +++ b/de/02.8.md @@ -23,10 +23,10 @@ In diesem Kapitel haben wir uns hauptsächlich mit den 25 Schlüsselwörtern in - `map` definiert eine Map, welche Hashtabellen in anderen Programmiersprachen ähneln. - `range` wird genutzt, um Daten aus einem `slice`, einer `map` oder einem`channel` zu erhalten. -Wenn Du verstanden was, wie die 25 Schlüsselwörter einzusetzen sind, dann hast Du bereits eine Menge über Go gelernt. +Wenn Du verstanden hast, wie die 25 Schlüsselwörter einzusetzen sind, dann hast Du bereits eine Menge über Go gelernt. ## Links - [Inhaltsverzeichnis](preface.md) - Vorheriger Abschnitt: [Nebenläufigkeit](02.7.md) -- Nächstes Kapitel: [Grundlagen des Internets](03.0.md) \ No newline at end of file +- Nächstes Kapitel: [Grundlagen des Internets](03.0.md)