happy go programming

178
Happy Go Part II Yo-An Lin (c9s) [email protected] [email protected]

Upload: yo-an-lin

Post on 08-Sep-2014

3.542 views

Category:

Technology


0 download

DESCRIPTION

golang, go, programming, web applications.

TRANSCRIPT

Page 2: Happy Go Programming

Intro

• was the GitHub Top 1 Contributor ( http://git.io/top )

• 3+ years Perl/VimL programming

• 3+ years PHP programming

• 2+ years Go programming

Page 3: Happy Go Programming

Go?

Page 4: Happy Go Programming

Ken Thompson

Rob Pike

Page 5: Happy Go Programming

Started since 2007

Page 6: Happy Go Programming

Announced in November 2009

Page 7: Happy Go Programming

Used in some of Google’s production system

Page 8: Happy Go Programming
Page 9: Happy Go Programming

What’s Go• Statically-Typed Language 靜態型別編譯語⾔言

• Built-in Concurrency 內建並發性⽀支持

• Statically-linked Native Binary 靜態連結原⽣生⼆二進位執⾏行檔

• Fast compilation times 極快速的編譯

• Remote package management 內建外部套件管理

• Garbage Collection 使⽤用垃圾收集器

• Safety 安全 (race conditions, type and memory safety for multithreaded program)

Page 10: Happy Go Programming

About The Language• Concise variable declaration 簡潔的變數定義

• Type Inference 型別推導

• Easy to use 簡易使⽤用

• Composition instead of Inheritance.

• Use Interface 使⽤用介⾯面取代 is-a 繼承

• multiple return value 多回傳值函數

Page 11: Happy Go Programming

About The Tools• 語⾔言規格的修改,可透過 go fix 來將舊版語法或程式碼做⾃自動修正

• 編碼⾵風格可透過 go fmt 來統⼀一所有格式,以及⾃自動去除空⽩白⾏行、換⾏行、縮排等等。 且可以⽤用 grammar 的⽅方式來描述語法。

• 內建 profiling tools 且⽀支持 Goole pprof ,可直接在 http server 上開 profiler API,利⽤用命令列⼯工具遠端取得 CPU, Memory 使⽤用狀況並進⾏行分析,或產⽣生 call graph 等等資料。

• 遠端套件可直接透過 go get 安裝

Page 12: Happy Go Programming

What’s the difference?那麼有什麼不同呢?

Page 13: Happy Go Programming

Interpreted language

Page 14: Happy Go Programming

Statically compiled language

Page 15: Happy Go Programming

Statically-typed (or compiled) languages are

usually faster

Page 16: Happy Go Programming

Benchmark

• Faster than Node.js, Python, Perl, PHP, Ruby (without C/C++ extensions)

• A bit slower than C, C++ and Java (sometimes faster than Java)

• Low memory footprint (10+ times lower than Java)

Page 17: Happy Go Programming

Benchmarkhttp://www.techempower.com/benchmarks/

Page 18: Happy Go Programming

and it compiles fast

Page 19: Happy Go Programming

But it costs a lot of time

Page 20: Happy Go Programming

But it costs a lot of time

Page 21: Happy Go Programming

Go solves this problem

Page 22: Happy Go Programming

Concurrency?

Page 23: Happy Go Programming

Prefork

Page 24: Happy Go Programming

Prefork

Page 25: Happy Go Programming

Prefork

Page 26: Happy Go Programming

Prefork

• Hard to share data between processes.

• Costs a lot of CPU cycle.

• Copying process is time consuming.

• Waste a lot of memory.

Page 27: Happy Go Programming

Just use Go Routine

Page 28: Happy Go Programming

Just use Go Routine

All in one process

Page 29: Happy Go Programming

Just use Go Routine

• Threaded worker pool

• use pipeline (channel) to communicate

• CSP (Communicating Sequential Processes)

http://golang.org/doc/faq

Page 30: Happy Go Programming

Easier Deployment

Page 31: Happy Go Programming

Deployment Pain• Install required packages

• Install application package dependencies

• (dependency hell)

• (incompatible version hell)

• (10 hours later…)

• ok, finally onlined.

Page 32: Happy Go Programming

You can just build & scp

Page 33: Happy Go Programming

And it works

Page 34: Happy Go Programming

Q & A Time

Page 35: Happy Go Programming

————————

Page 36: Happy Go Programming

Ready For Production?

Page 37: Happy Go Programming

Companies using Go• Google

• Sound Cloud

• BCC

• Canonical

• Heroku

• Carbon Games

• Iron.io

• SmugMug

• Bitly

• CloudFlare

Page 38: Happy Go Programming

Enough Open Sourced Packages?

Page 39: Happy Go Programming

15,298 packageshttp://godoc.org/-/index

Page 40: Happy Go Programming

Is it popular?

Page 41: Happy Go Programming
Page 42: Happy Go Programming

Supported OS?

Page 43: Happy Go Programming

Supported OS• Linux

• BSD, OpenBSD

• Windows

• Mac OS

• Plan 9

Page 44: Happy Go Programming

Architectures?

Page 45: Happy Go Programming

Architectures

• i386

• amd64

• arm

Page 46: Happy Go Programming

Development Environment

For Go

Page 47: Happy Go Programming

Go IDE• Sublime Text 2

• IntelliJ

• LiteIDE

• Intype

• NetBeans

• Eclipse

• Zeus

http://geekmonkey.org/articles/20-comparison-of-ides-for-google-go

Page 48: Happy Go Programming

go/misc• misc/vim : generic vim plugin

• misc/emacs : emacs go mode

• misc/git : pre-commit hook (run go fmt before commmit)

• misc/bash : bash completion

• zsh/go : zsh completion

• misc/cgo : cgo examples

Page 49: Happy Go Programming

vim: gocode

• go completion daemon

• vim omni completion support

• scan code from $GOPATH

Page 50: Happy Go Programming

Go Environment

• $GOROOT ( defaults to /usr/local/go )

• $GOPATH ( your packages )

• $GOARCH

• $GOOS

Page 51: Happy Go Programming

$GOPATH

mkdir ~/go export GOPATH=~/go

執⾏行 go get 時,packages 會安裝到 GOPATH 第⼀一個 path 內

Page 52: Happy Go Programming

$GOPATH

mkdir ~/go/vendor mkdir ~/go/private export GOPATH=~/go/vendor:~/go/private

可利⽤用 $GOPATH 將私⽤用 package 分開

Page 53: Happy Go Programming

$GOPATHmkdir ~/go export GOPATH=~/go

path description

~/go/src your source code

~/go/pkg compiled packages (*.a)

~/go/bin command-line binary

Page 54: Happy Go Programming

Hello World$ vim hello.go

package main !import "fmt" !func main() { fmt.Printf("hello, world\n") }

Page 55: Happy Go Programming

Hello World

$ go run hello.go

$ go build -o hello hello.go $ ./hello

Page 56: Happy Go Programming

Go commands

• go run 編譯後執⾏行程式 (必須是 main package)

• go build 編譯

• go install 編譯並且安裝

• go get 抓取遠端套件並且編譯安裝

Page 57: Happy Go Programming

Basic Application

Page 58: Happy Go Programming

Basic Application

package main!import "fmt"!func main() { fmt.Println("anything here")}

Page 59: Happy Go Programming

Basic commands

• go build app.go go build -x app.go

• go run app.gogo run -x app.go

• go install

Page 60: Happy Go Programming

Types

Page 61: Happy Go Programming

Types

• int, int8, int16, int32, int64,

• float32, float64

• string

• byte

Page 62: Happy Go Programming

Basic Type Conversion

var a int32 = 32var b int64 = int64(a)var c int = int(a)

Page 63: Happy Go Programming

Basic Type Conversion

var str = "Hello World" var data []byte = []byte(str) fmt.Println(data)

Page 64: Happy Go Programming

Basic Type Conversion

var str = "Hello World" var data []byte = []byte(str) fmt.Println(data)

[72 101 108 108 111 32 87 111 114 108 100]

Page 65: Happy Go Programming

Slice & Array

Page 66: Happy Go Programming

Slice & Array Type

• Array: [10]int, [3]int

• Slice: []int, []string, []byte

Page 67: Happy Go Programming

Slice & Array• Array: list := […]int{1,2,3,4,5 } list := [5]int{ 1,2,3,4,5 }

• Slice: list := []int{ 1, 2, 3 } list := []string{ “foo”, “bar”, “zoo” }

Page 68: Happy Go Programming

Slice & Array• Array: var list = […]int{1,2,3,4,5 } var list = [5]int{ 1,2,3,4,5 }

• Slice: var list = []int{ 1, 2, 3 } var list = []string{ “foo”, “bar”, “zoo” }

Page 69: Happy Go Programming

Slice & Array• Array: var list [5]int = […]int{1,2,3,4,5 } var list [5]int = [5]int{ 1,2,3,4,5 }

• Slice: var list []int = []int{ 1, 2, 3 } var list []string = []string{ “foo”, “bar”, “zoo” }

Page 70: Happy Go Programming

Slice 切⽚片

Page 71: Happy Go Programming

Slice - appending

names := []string{"Mary", "Lily", "July"} names = append(names, "Jane")

Page 72: Happy Go Programming

Slice - iterating

names := []string{“Mary","Lily","July"}! for i, name := range names { fmt.Println(i, name) }

Page 73: Happy Go Programming

String = Slice of bytea string is in effect a read-only slice of bytes

Page 74: Happy Go Programming

Slice - string• string is basically a slice of byte.

• slice is immutable, string is also immutable.

• which means: “no delete or insert in specific position”

• but you can create a new slice references to another slice with position and length.

Page 75: Happy Go Programming

Slice - string

var str = "abcdefg" fmt.Printf("str[0] = byte: %#v\n", str[0]) fmt.Printf("str[2:5] = []byte: %#v\n", str[2:5])

str[0] = byte: 0x61str[2:5] = []byte: "cde"

Page 76: Happy Go Programming

Slice - string

var str = "abcdefg" for i, c := range str { fmt.Printf("str[%d] = %c\n", i, c) }

str[0] = astr[1] = bstr[2] = cstr[3] = dstr[4] = estr[5] = fstr[6] = g

Page 77: Happy Go Programming

More about stringhttp://blog.golang.org/strings

Page 78: Happy Go Programming

Slice - internals

Page 79: Happy Go Programming

Slice internals: slice header

[]byte{ 60, 61, 62, 63, 64 }

Page 80: Happy Go Programming

Slice internal: slice header

// this creates a slice with header: // start from 0 // length = 7 // data = pointer to the int array. foo := []int{0, 1, 2, 3, 4, 5, 6}! // this copy the slice header to the function addOne(foo)

Page 81: Happy Go Programming

Slice internal: slice header

// we get a copy of slice headerfunc addOne(list []int) { for i, _ := range list { // this modify the actual data // through the data pointer. list[i]++ }}

Page 82: Happy Go Programming

Slice - internalsx := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x

Page 83: Happy Go Programming

Slice - internalsx := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x

Page 84: Happy Go Programming

Slice - internalsx := [3]string{"Лайка", "Белка", "Стрелка"}s := x[:] // a slice referencing the storage of x

Page 85: Happy Go Programming

Slice - internals

s = s[2:4]

Page 86: Happy Go Programming

Slice - internals

s = s[2:4]

Page 87: Happy Go Programming

Slice - internals

s = s[2:4]

Slicing does not copy the slice's data. It creates a new slice header that points to the original array.

Page 88: Happy Go Programming

Slice - internals

s = s[:cap(s)]

Page 89: Happy Go Programming

Slice - internals

s = s[:cap(s)]

Page 90: Happy Go Programming

More About Slicehttp://blog.golang.org/slices

http://blog.golang.org/go-slices-usage-and-internals

Page 91: Happy Go Programming

Map

Page 92: Happy Go Programming

Map

contacts := map[string]string {}

Type of Key

Page 93: Happy Go Programming

Map

contacts := map[string]string {}

Type of Value

Page 94: Happy Go Programming

Map

contacts := map[string]string {}

contacts := map[string]string { "Jack": "02-2345678",}

Page 95: Happy Go Programming

Map

contacts := map[string]string {}

contacts := map[string]string { "Jack": "02-2345678",}

Initialised Key Initialised Value

Page 96: Happy Go Programming

Map

contacts := map[string]string {}

contacts := map[string]string { "Jack": "02-2345678",}

“,” Composite Literal Syntax

Page 97: Happy Go Programming

Map

contacts := map[string]string {}

contacts := map[string]string { "Jack": “02-2345678", "Lisa": "1234567890",}

“,” Composite Literal Syntax

Page 98: Happy Go Programming

Map

var contacts map[string]string = map[string]string { “Jack”: "02-2345678", }

Page 99: Happy Go Programming

Map - assign

contacts := map[string]string{}!

contacts["key"] = "value"

Page 100: Happy Go Programming

Map - defined

contacts := map[string]string{}!

if _, ok := contacts["key"]; ok {!

} Multiple Return Value

Page 101: Happy Go Programming

Map - defined

contacts := map[string]string{}!

if _, ok := contacts["key"]; ok {!

}Variable Assignment

Page 102: Happy Go Programming

Map - defined

contacts := map[string]string{}!

if _, ok := contacts["key"]; ok {!

} boolean context

Page 103: Happy Go Programming

Map - defined

contacts := map[string]string{}!

if _, ok := contacts["key"]; ok {!

} boolean: if found

Page 104: Happy Go Programming

Map - defined

contacts := map[string]string{}!

if _, ok := contacts["key"]; ok {!

} actual value with the defined type

Page 105: Happy Go Programming

Map - defined

if val, ok := contacts["key"]; ok { _ = val }

Unused Variable

Page 106: Happy Go Programming

Map - delete

Built-in Function contacts := map[string]string{} contacts["key"] = "value" delete(contacts, “key")

Page 107: Happy Go Programming

Map - iterating

contacts["key"] = "value" contacts["key2"] = “value2"! for key, val := range contacts { _ = key _ = val }

Page 108: Happy Go Programming

Pointer & Reference

Page 109: Happy Go Programming

Pointer

• pointer is basically like we used in C.

• easy to use but safer than C.

• no segmentation-fault.!

• compile-time type checking.

Page 110: Happy Go Programming

Pointer: new & make

• new() - doesn’t initialise value. zero-ed memory allocation.!

• make() - allocation with data initialisation.

Page 111: Happy Go Programming

Pointer

a := new(int) fmt.Println(a) fmt.Println(*a)

Page 112: Happy Go Programming

Pointer

a := new(int) fmt.Println(a) fmt.Println(*a)

0x2101ef0180

Page 113: Happy Go Programming

Reference

var a int = 10 var b *int = &a a = 12 fmt.Println(a, *b) 12 12

Page 114: Happy Go Programming

Struct

Page 115: Happy Go Programming

Struct

• similar to the struct we used in C.

• but you can embed another struct in your struct. so called “embedded struct”

Page 116: Happy Go Programming

Structtype Contact struct { Name string Phone string}

Page 117: Happy Go Programming

Structtype Contact struct { Name string Phone string}

The type name

Page 118: Happy Go Programming

Structtype Contact struct { Name string Phone string}

The type of “Contact “ is a struct

Page 119: Happy Go Programming

Structtype Contact struct { Name string Phone string}

Struct Field Name

Page 120: Happy Go Programming

Structtype Contact struct { Name string Phone string}

Field Type

Page 121: Happy Go Programming

Struct Allocation

func main() { p1 := Contact{Name: "Lisa", Phone: "1234"} p2 := Contact{"Mary", "2345"} fmt.Println(p1, p2)}

Page 122: Happy Go Programming

Composite Literal

a := [...]string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}s := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}

Page 123: Happy Go Programming

Struct Allocation

p1 := Contact{Name: "Lisa", Phone: "1234"}

p1 := Contact{"Lisa", "1234"}

…Equals To…

Page 124: Happy Go Programming

Struct Allocation

The expressions new(File) and &File{} are equivalent.

new(File)&File{}

Page 125: Happy Go Programming

Accessing Struct Fields

contact1 := Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

Use “.” to access struct field

Page 126: Happy Go Programming

Accessing Struct Fields

contact1 := Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

contact2 := &Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

Allocate a struct and return the reference

Page 127: Happy Go Programming

Accessing Struct Fields

contact1 := Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

contact2 := &Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

Pointer of type Contact

Page 128: Happy Go Programming

Accessing Struct Fields

contact1 := Contact{"Mary", "12345678"}fmt.Println(contact1.Name)

contact2 := &Contact{"Mary", "12345678"}fmt.Println(contact2.Name)

Always use “.” to access struct field

Page 129: Happy Go Programming

Custom Type

Page 130: Happy Go Programming

Custom Types

type Score inttype ScoreMap map[string]inttype NickName string

Page 131: Happy Go Programming

Custom Types

type Score inttype ScoreMap map[string]inttype NickName string

type Score is a int type

Page 132: Happy Go Programming

Custom Typestype Score int!func CalculateScore(a Score, b Score) Score { return a + b} Strict type of your data makes your

application safer.

Page 133: Happy Go Programming

Custom Typestype Score int!func CalculateScore(a Score, b Score) Score { return a + b} Strict type of your data makes your

application safer.

CalculateScore( 20 ) Compilation Fail

Page 134: Happy Go Programming

Custom Typestype Score int!func CalculateScore(a Score, b Score) Score { return a + b} Strict type of your data makes your

application safer.

CalculateScore( 20 )CalculateScore( Score(20) )

Compilation FailCompilation Pass

Page 135: Happy Go Programming

Type Methods

type NickName string!func (self NickName) Say() { fmt.Println(self)}

Page 136: Happy Go Programming

Type Methods

type NickName string!func (self NickName) Say() { fmt.Println(self)}

Receiver

Page 137: Happy Go Programming

Type Methods

type NickName string!func (self * NickName) Say() { fmt.Println(self)}

You may also use the reference. (faster)

Page 138: Happy Go Programming

Type Methods

a := NickName("foo")a.Say()

Allocate a string

Page 139: Happy Go Programming

Type Methods

a := NickName("foo")a.Say()

Type cast to NickName

Page 140: Happy Go Programming

Type Methods

a := NickName("foo")a.Say()

b := &ab.Say()

Page 141: Happy Go Programming

Type Methods

a := NickName("foo")a.Say()

b := &ab.Say()Always use “.” to access fields or methods .

Page 142: Happy Go Programming

Interface

Page 143: Happy Go Programming

Interface

• interface defines the requirement of the object method prototype.

• you define the requirement and check the requirement in both compile-time and runtime.

Page 144: Happy Go Programming

interface

type Worker interface { Work()}

Page 145: Happy Go Programming

interfacetype Worker interface { Work()}

type SeedWorker struct{}!func (self *SeedWorker) Work() { // work...}

Page 146: Happy Go Programming

interface// accept anything implements // the interface of Workerfunc HandleData(worker Worker) { worker.Work()}!func main() { HandleData(SeedWorker{}) HandleData(&SeedWorker{})}

Page 147: Happy Go Programming

interface{}

• interface{} is basically a universal pointer.

• just like “id” we used in Objective-C

• just like the void pointer we used in C.

• interface{} means an interface without requirement.

Page 148: Happy Go Programming

interface{}

type Foo struct{}type Bar struct{}

Given Struct Foo and Bar

Page 149: Happy Go Programming

interface{}

type Foo struct{}type Bar struct{}

Given Struct Foo and Bar

var a interface{} = Foo{} var b interface{} = &Foo{} var c interface{} = &Bar{} b = c a = b

Page 150: Happy Go Programming

interface{}

type anything interface{}

var a anything = Foo{}var b anything = &Foo{}var c anything = &Bar{}

Page 151: Happy Go Programming

interface{}

func AcceptAnything(a anything) { // do something}func main() { AcceptAnything(Foo{}) AcceptAnything(&Foo{}) AcceptAnything(&Bar{})}

type anything interface{}

Page 152: Happy Go Programming

Building Web Applications

Using net/http

Page 153: Happy Go Programming

Data Structure For Page

$ mkdir wiki$ cd wiki$ vim page.go

Page 154: Happy Go Programming

Data Structure For Pagepackage main!import ( "fmt" "io/ioutil")

Page 155: Happy Go Programming

Data Structure For Pagetype Page struct { Title string Body []byte}

Page 156: Happy Go Programming

Data Structure For Pagetype Page struct { Title string Body []byte}

func (p *Page) save() error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600)}

Page 157: Happy Go Programming

Data Structure For Pagefunc loadPage(title string) (*Page, error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } return &Page{Title: title, Body: body}, nil}

Page 158: Happy Go Programming

Build it!

$ go build wiki.go

Page 159: Happy Go Programming

Build it!

$ go build wiki.go$ ./wikiThis is a sample page.

Page 160: Happy Go Programming

Introducing net/httppackage main!import ( "fmt" "net/http")

Page 161: Happy Go Programming

Introducing net/http

func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}

Type of Handler

Page 162: Happy Go Programming

Introducing net/http

func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}

Resource handle which implements Writer interface.

Page 163: Happy Go Programming

Introducing net/http

func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}

Call w.Write… (this satisfies Writer interface)

Page 164: Happy Go Programming

Introducing net/http

func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}!func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil)}

Calls the HandleFunc function in “http” package. This function accepts a function pointer which satisfies the interface.

Page 165: Happy Go Programming

Introducing net/http

func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])}!func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil)}

Binds HTTP server to “:8080”

Page 166: Happy Go Programming

Introducing net/http

http://localhost:8080/monkeys

Hi there, I love monkeys!

Page 167: Happy Go Programming

Using net/httppackage main!import ( "fmt" "io/ioutil" "net/http")

Import http package.

Page 168: Happy Go Programming

Using net/httpfunc viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)}

The URL of current request

Page 169: Happy Go Programming

Using net/httpfunc viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)}

Strip the first 6 bytes from URL Path

Page 170: Happy Go Programming

Using net/httpfunc viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body)}

Load the page data from file.

Page 171: Happy Go Programming

Using net/http

func main() { http.HandleFunc("/view/", viewHandler) http.ListenAndServe(":8080", nil)}

Page 172: Happy Go Programming

Build it!

$ go build wiki.go

Page 173: Happy Go Programming

Build it!

$ vim test.txt$ go build wiki.go$ ./wiki$ curl http://localhost:8080/view/test

Page 174: Happy Go Programming

Edit handlerfunc editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] p, err := loadPage(title) if err != nil { p = &Page{Title: title} } fmt.Fprintf(w, "<h1>Editing %s</h1>"+ "<form action=\"/save/%s\" method=\"POST\">"+ "<textarea name=\"body\">%s</textarea><br>"+ "<input type=\"submit\" value=\"Save\">"+ "</form>", p.Title, p.Title, p.Body)}

Page 175: Happy Go Programming

The html/template package

package main!import ( "html/template" "io/ioutil" "net/http")

Page 176: Happy Go Programming

The html/template package

func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] p, err := loadPage(title) if err != nil { p = &Page{Title: title} } t, _ := template.ParseFiles("edit.html") t.Execute(w, p)}

Page 177: Happy Go Programming

The html/template package

<h1>Editing {{.Title}}</h1>!<form action="/save/{{.Title}}" method="POST"><div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div><div><input type="submit" value="Save"></div></form>

Page 178: Happy Go Programming

Save handlerfunc saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/save/"):] body := r.FormValue("body") p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound)}!http.HandleFunc(“/save/“, saveHandler)!http://localhost:8080/edit/test # access test.txt