fa directory created
This commit is contained in:
7
fa/code/readme.md
Normal file
7
fa/code/readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## Workspace setup.
|
||||
|
||||
To avoid workspace issues and be able to develop from any folder within this path,
|
||||
set the environment variable `GOPATH` to the path of this directory.
|
||||
|
||||
More info:
|
||||
- [GOPATH documentation](http://golang.org/doc/code.html#GOPATH)
|
||||
14
fa/code/src/apps/ch.1.2/main.go
Normal file
14
fa/code/src/apps/ch.1.2/main.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Example code for Chapter 1.2 from "Build Web Application with Golang"
|
||||
// Purpose: Run this file to check if your workspace is setup correctly.
|
||||
// To run, navigate to the current directory in a console and type `go run main.go`
|
||||
// If the text "Hello World" isn't shown, then setup your workspace again.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mymath"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
|
||||
}
|
||||
11
fa/code/src/apps/ch.2.1/main.go
Normal file
11
fa/code/src/apps/ch.2.1/main.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// Example code for Chapter ? from "Build Web Application with Golang"
|
||||
// Purpose: Hello world example demonstrating UTF-8 support.
|
||||
// To run in the console, type `go run main.go`
|
||||
// You're missing language fonts, if you're seeing squares or question marks.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界\n")
|
||||
}
|
||||
277
fa/code/src/apps/ch.2.2/main.go
Normal file
277
fa/code/src/apps/ch.2.2/main.go
Normal file
@@ -0,0 +1,277 @@
|
||||
// Example code for Chapter 2.2 from "Build Web Application with Golang"
|
||||
// Purpose: Goes over the assignment and manipulation of basic data types.
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// constants
|
||||
const Pi = 3.1415926
|
||||
|
||||
// booleans default to `false`
|
||||
var isActive bool // global variable
|
||||
var enabled, disabled = true, false // omit type of variables
|
||||
|
||||
// grouped definitions
|
||||
const (
|
||||
i = 1e4
|
||||
MaxThread = 10
|
||||
prefix = "astaxie_"
|
||||
)
|
||||
|
||||
var (
|
||||
frenchHello string // basic form to define string
|
||||
emptyString string = "" // define a string with empty string
|
||||
)
|
||||
|
||||
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
|
||||
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`.
|
||||
vname1, vname2, vname3 := v1, v2, v3
|
||||
|
||||
// `_` disregards the returned value.
|
||||
_, b := 34, 35
|
||||
|
||||
fmt.Printf("vname1 = %v, vname2 = %v, vname3 = %v\n", vname1, vname2, vname3)
|
||||
fmt.Printf("v1 = %v, v2 = %v, v3 = %v\n", v1, v2, v3)
|
||||
fmt.Println("b =", b)
|
||||
}
|
||||
func show_bool() {
|
||||
fmt.Println("show_bool()")
|
||||
var available bool // local variable
|
||||
valid := false // Shorthand assignment
|
||||
available = true // assign value to variable
|
||||
|
||||
fmt.Printf("valid = %v, !valid = %v\n", valid, !valid)
|
||||
fmt.Printf("available = %v\n", available)
|
||||
}
|
||||
func show_different_types() {
|
||||
fmt.Println("show_different_types()")
|
||||
var (
|
||||
unicodeChar rune
|
||||
a int8
|
||||
b int16
|
||||
c int32
|
||||
d int64
|
||||
e byte
|
||||
f uint8
|
||||
g int16
|
||||
h uint32
|
||||
i uint64
|
||||
)
|
||||
var cmplx complex64 = 5 + 5i
|
||||
|
||||
fmt.Println("Default values for int types")
|
||||
fmt.Println(unicodeChar, a, b, c, d, e, f, g, h, i)
|
||||
|
||||
fmt.Printf("Value is: %v\n", cmplx)
|
||||
}
|
||||
func show_strings() {
|
||||
fmt.Println("show_strings()")
|
||||
no, yes, maybe := "no", "yes", "maybe" // brief statement
|
||||
japaneseHello := "Ohaiyou"
|
||||
frenchHello = "Bonjour" // basic form of assign values
|
||||
|
||||
fmt.Println("Random strings")
|
||||
fmt.Println(frenchHello, japaneseHello, no, yes, maybe)
|
||||
|
||||
// The backtick, `, will not escape any character in a string
|
||||
fmt.Println(`This
|
||||
is on
|
||||
multiple lines`)
|
||||
}
|
||||
func show_string_manipulation() {
|
||||
fmt.Println("show_string_manipulation()")
|
||||
var s string = "hello"
|
||||
|
||||
//You can't do this with strings
|
||||
//s[0] = 'c'
|
||||
|
||||
s = "hello"
|
||||
c := []byte(s) // convert string to []byte type
|
||||
c[0] = 'c'
|
||||
s2 := string(c) // convert back to string type
|
||||
|
||||
m := " world"
|
||||
a := s + m
|
||||
|
||||
d := "c" + s[1:] // you cannot change string values by index, but you can get values instead.
|
||||
fmt.Printf("%s\n", d)
|
||||
|
||||
fmt.Printf("s = %s, c = %v\n", s, c)
|
||||
fmt.Printf("s2 = %s\n", s2)
|
||||
fmt.Printf("combined strings\na = %s, d = %s\n", a, d)
|
||||
}
|
||||
func show_errors() {
|
||||
fmt.Println("show_errors()")
|
||||
err := errors.New("Example error message\n")
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
}
|
||||
func show_iota() {
|
||||
fmt.Println("show_iota()")
|
||||
const (
|
||||
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.
|
||||
)
|
||||
|
||||
const v = iota // once iota meets keyword `const`, it resets to `0`, so v = 0.
|
||||
|
||||
const (
|
||||
e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line.
|
||||
)
|
||||
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.
|
||||
func This_is_public() {}
|
||||
func this_is_private() {}
|
||||
|
||||
func set_default_values() {
|
||||
// default values for the types.
|
||||
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
|
||||
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
|
||||
|
||||
a := [3]int{1, 2, 3} // define a int array with 3 elements
|
||||
|
||||
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.
|
||||
|
||||
c := [...]int{4, 5, 6} // use `…` replace with number of length, Go will calculate it for you.
|
||||
|
||||
// define a two-dimensional array with 2 elements, and each element has 4 elements.
|
||||
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.
|
||||
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 last element is %d\n", arr[9])
|
||||
//it returns default value of 10th element in this array, which is 0 in this case.
|
||||
|
||||
fmt.Println("array a =", a)
|
||||
fmt.Println("array b =", b)
|
||||
fmt.Println("array c =", c)
|
||||
|
||||
fmt.Println("array doubleArray =", doubleArray)
|
||||
fmt.Println("array easyArray =", easyArray)
|
||||
}
|
||||
func show_slices() {
|
||||
fmt.Println("show_slices()")
|
||||
// define a slice with 10 elements which types are byte
|
||||
var ar = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
|
||||
|
||||
// define two slices with type []byte
|
||||
var a, b []byte
|
||||
|
||||
// a points to elements from 3rd to 5th in array ar.
|
||||
a = ar[2:5]
|
||||
// now a has elements ar[2]、ar[3] and ar[4]
|
||||
|
||||
// b is another slice of array ar
|
||||
b = ar[3:5]
|
||||
// now b has elements ar[3] and ar[4]
|
||||
|
||||
// define an array
|
||||
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
|
||||
// define two 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
|
||||
|
||||
// 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
|
||||
|
||||
fmt.Println("slice ar =", ar)
|
||||
fmt.Println("slice a =", a)
|
||||
fmt.Println("slice b =", b)
|
||||
fmt.Println("array =", array)
|
||||
fmt.Println("slice aSlice =", aSlice)
|
||||
fmt.Println("slice bSlice =", bSlice)
|
||||
fmt.Println("len(bSlice) =", len(bSlice))
|
||||
}
|
||||
func show_map() {
|
||||
fmt.Println("show_map()")
|
||||
// use string as key type, int as value type, and you have to use `make` initialize it.
|
||||
var numbers map[string]int
|
||||
// another way to define map
|
||||
numbers = make(map[string]int)
|
||||
numbers["one"] = 1 // assign value by key
|
||||
numbers["ten"] = 10
|
||||
numbers["three"] = 3
|
||||
|
||||
// Initialize a 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
|
||||
|
||||
// map has two return values. For second value, if the key doesn't exist,ok is false,true otherwise.
|
||||
csharpRating, ok := rating["C#"]
|
||||
if ok {
|
||||
fmt.Println("C# is in the map and its rating is ", csharpRating)
|
||||
} else {
|
||||
fmt.Println("We have no rating associated with C# in the map")
|
||||
}
|
||||
|
||||
delete(rating, "C") // delete element with key "c"
|
||||
fmt.Printf("map rating = %#v\n", rating)
|
||||
}
|
||||
func main() {
|
||||
show_multiple_assignments()
|
||||
show_bool()
|
||||
show_different_types()
|
||||
show_strings()
|
||||
show_string_manipulation()
|
||||
show_errors()
|
||||
show_iota()
|
||||
set_default_values()
|
||||
show_arrays()
|
||||
show_slices()
|
||||
show_map()
|
||||
}
|
||||
8
fa/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go
Normal file
8
fa/code/src/apps/ch.2.2/what_is_wrong_with_this/main.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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`
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var i int
|
||||
}
|
||||
26
fa/code/src/apps/ch.2.3/basic_functions/main.go
Normal file
26
fa/code/src/apps/ch.2.3/basic_functions/main.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Creating a basic function
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// return greater value between a and b
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func main() {
|
||||
x := 3
|
||||
y := 4
|
||||
z := 5
|
||||
|
||||
max_xy := max(x, y) // call function max(x, y)
|
||||
max_xz := max(x, z) // call function max(x, z)
|
||||
|
||||
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
|
||||
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
|
||||
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y, z)) // call function here
|
||||
}
|
||||
14
fa/code/src/apps/ch.2.3/hidden_print_methods/main.go
Normal file
14
fa/code/src/apps/ch.2.3/hidden_print_methods/main.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// As of Google go 1.1.2, `println()` and `print()` are hidden functions included from the runtime package.
|
||||
// However it's encouraged to use the print functions from the `fmt` package.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f() {
|
||||
fmt.Println("First")
|
||||
print("Second ")
|
||||
println(" Third")
|
||||
}
|
||||
func main() {
|
||||
f()
|
||||
}
|
||||
26
fa/code/src/apps/ch.2.3/import_packages/main.go
Normal file
26
fa/code/src/apps/ch.2.3/import_packages/main.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows different ways of importing a package.
|
||||
// Note: For the package `only_call_init`, we reference the path from the
|
||||
// base directory of `$GOPATH/src`. The reason being Golang discourage
|
||||
// the use of relative paths when import packages.
|
||||
// BAD: "./only_call_init"
|
||||
// GOOD: "apps/ch.2.3/import_packages/only_call_init"
|
||||
package main
|
||||
|
||||
import (
|
||||
// `_` will only call init() inside the package only_call_init
|
||||
_ "apps/ch.2.3/import_packages/only_call_init"
|
||||
f "fmt" // import the package as `f`
|
||||
. "math" // makes the public methods and constants global
|
||||
"mymath" // custom package located at $GOPATH/src/
|
||||
"os" // normal import of a standard package
|
||||
"text/template" // the package takes the name of last folder path, `template`
|
||||
)
|
||||
|
||||
func main() {
|
||||
f.Println("mymath.Sqrt(4) =", mymath.Sqrt(4))
|
||||
f.Println("E =", E) // references math.E
|
||||
|
||||
t, _ := template.New("test").Parse("Pi^2 = {{.}}")
|
||||
t.Execute(os.Stdout, Pow(Pi, 2))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package only_call_init
|
||||
|
||||
import "fmt"
|
||||
|
||||
func init() {
|
||||
fmt.Println("only_call_init.init() was called.")
|
||||
}
|
||||
142
fa/code/src/apps/ch.2.3/main.go
Normal file
142
fa/code/src/apps/ch.2.3/main.go
Normal file
@@ -0,0 +1,142 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Goes over if, else, switch conditions, loops and defer.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func computedValue() int {
|
||||
return 1
|
||||
}
|
||||
func show_if() {
|
||||
fmt.Println("\n#show_if()")
|
||||
x := computedValue()
|
||||
integer := 23
|
||||
|
||||
fmt.Println("x =", x)
|
||||
fmt.Println("integer =", integer)
|
||||
if x > 10 {
|
||||
fmt.Println("x is greater than 10")
|
||||
} else {
|
||||
fmt.Println("x is less than 10")
|
||||
}
|
||||
|
||||
if integer == 3 {
|
||||
fmt.Println("The integer is equal to 3")
|
||||
} else if integer < 3 {
|
||||
fmt.Println("The integer is less than 3")
|
||||
} else {
|
||||
fmt.Println("The integer is greater than 3")
|
||||
}
|
||||
}
|
||||
func show_if_var() {
|
||||
fmt.Println("\n#show_if_var()")
|
||||
// initialize x, then check if x greater than
|
||||
if x := computedValue(); x > 10 {
|
||||
fmt.Println("x is greater than 10")
|
||||
} else {
|
||||
fmt.Println("x is less than 10")
|
||||
}
|
||||
|
||||
// the following code will not compile, since `x` is only accessible with the if/else block
|
||||
// fmt.Println(x)
|
||||
}
|
||||
func show_goto() {
|
||||
fmt.Println("\n#show_goto()")
|
||||
// The call to the label switches the goroutine it seems.
|
||||
i := 0
|
||||
Here: // label ends with ":"
|
||||
fmt.Println(i)
|
||||
i++
|
||||
if i < 10 {
|
||||
goto Here // jump to label "Here"
|
||||
}
|
||||
}
|
||||
func show_for_loop() {
|
||||
fmt.Println("\n#show_for_loop()")
|
||||
sum := 0
|
||||
for index := 0; index < 10; index++ {
|
||||
sum += index
|
||||
}
|
||||
fmt.Println("part 1, sum is equal to ", sum)
|
||||
|
||||
sum = 1
|
||||
// The compiler will remove the `;` from the line below.
|
||||
// for ; sum < 1000 ; {
|
||||
for sum < 1000 {
|
||||
sum += sum
|
||||
}
|
||||
fmt.Println("part 2, sum is equal to ", sum)
|
||||
|
||||
for index := 10; 0 < index; index-- {
|
||||
if index == 5 {
|
||||
break // or continue
|
||||
}
|
||||
fmt.Println(index)
|
||||
}
|
||||
|
||||
}
|
||||
func show_loop_through_map() {
|
||||
fmt.Println("\n#show_loop_through_map()")
|
||||
m := map[string]int{
|
||||
"one": 1,
|
||||
"two": 2,
|
||||
"three": 3,
|
||||
}
|
||||
fmt.Println("map value = ", m)
|
||||
for k, v := range m {
|
||||
fmt.Println("map's key: ", k)
|
||||
fmt.Println("map's value: ", v)
|
||||
}
|
||||
}
|
||||
func show_switch() {
|
||||
fmt.Println("\n#show_switch()")
|
||||
i := 10
|
||||
switch i {
|
||||
case 1:
|
||||
fmt.Println("i is equal to 1")
|
||||
case 2, 3, 4:
|
||||
fmt.Println("i is equal to 2, 3 or 4")
|
||||
case 10:
|
||||
fmt.Println("i is equal to 10")
|
||||
default:
|
||||
fmt.Println("All I know is that i is an integer")
|
||||
}
|
||||
|
||||
integer := 6
|
||||
fmt.Println("integer =", integer)
|
||||
switch integer {
|
||||
case 4:
|
||||
fmt.Println("integer == 4")
|
||||
fallthrough
|
||||
case 5:
|
||||
fmt.Println("integer <= 5")
|
||||
fallthrough
|
||||
case 6:
|
||||
fmt.Println("integer <= 6")
|
||||
fallthrough
|
||||
case 7:
|
||||
fmt.Println("integer <= 7")
|
||||
fallthrough
|
||||
case 8:
|
||||
fmt.Println("integer <= 8")
|
||||
fallthrough
|
||||
default:
|
||||
fmt.Println("default case")
|
||||
}
|
||||
}
|
||||
func show_defer() {
|
||||
fmt.Println("\nshow_defer()")
|
||||
defer fmt.Println("(last defer)")
|
||||
for i := 0; i < 5; i++ {
|
||||
defer fmt.Printf("%d ", i)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
show_if()
|
||||
show_if_var()
|
||||
show_goto()
|
||||
show_for_loop()
|
||||
show_loop_through_map()
|
||||
show_switch()
|
||||
show_defer()
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.3/panic_and_recover/main.go
Normal file
31
fa/code/src/apps/ch.2.3/panic_and_recover/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Showing how to use `panic()` and `recover()`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var user = os.Getenv("USER")
|
||||
|
||||
func check_user() {
|
||||
if user == "" {
|
||||
panic("no value for $USER")
|
||||
}
|
||||
fmt.Println("Environment Variable `USER` =", user)
|
||||
}
|
||||
func throwsPanic(f func()) (b bool) {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
fmt.Println("Panic message =", x);
|
||||
b = true
|
||||
}
|
||||
}()
|
||||
f() // if f causes panic, it will recover
|
||||
return
|
||||
}
|
||||
func main(){
|
||||
didPanic := throwsPanic(check_user)
|
||||
fmt.Println("didPanic =", didPanic)
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.3/pass_by_value_and_pointer/main.go
Normal file
31
fa/code/src/apps/ch.2.3/pass_by_value_and_pointer/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows passing a variable by value and reference
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func add_by_value(a int) int {
|
||||
a = a + 1
|
||||
return a
|
||||
}
|
||||
func add_by_reference(a *int) int {
|
||||
*a = *a + 1
|
||||
return *a
|
||||
}
|
||||
func show_add_by_value() {
|
||||
x := 3
|
||||
fmt.Println("x = ", x)
|
||||
fmt.Println("add_by_value(x) =", add_by_value(x) )
|
||||
fmt.Println("x = ", x)
|
||||
}
|
||||
func show_add_by_reference() {
|
||||
x := 3
|
||||
fmt.Println("x = ", x)
|
||||
// &x pass memory address of x
|
||||
fmt.Println("add_by_reference(&x) =", add_by_reference(&x) )
|
||||
fmt.Println("x = ", x)
|
||||
}
|
||||
func main() {
|
||||
show_add_by_value()
|
||||
show_add_by_reference()
|
||||
}
|
||||
44
fa/code/src/apps/ch.2.3/type_function/main.go
Normal file
44
fa/code/src/apps/ch.2.3/type_function/main.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to define a function type
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type testInt func(int) bool // define a function type of variable
|
||||
|
||||
func isOdd(integer int) bool {
|
||||
if integer%2 == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isEven(integer int) bool {
|
||||
if integer%2 == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// pass the function `f` as an argument to another function
|
||||
|
||||
func filter(slice []int, f testInt) []int {
|
||||
var result []int
|
||||
for _, value := range slice {
|
||||
if f(value) {
|
||||
result = append(result, value)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
func init() {
|
||||
fmt.Println("\n#init() was called.")
|
||||
}
|
||||
func main() {
|
||||
slice := []int{1, 2, 3, 4, 5, 7}
|
||||
fmt.Println("slice = ", slice)
|
||||
odd := filter(slice, isOdd) // use function as values
|
||||
fmt.Println("Odd elements of slice are: ", odd)
|
||||
even := filter(slice, isEven)
|
||||
fmt.Println("Even elements of slice are: ", even)
|
||||
}
|
||||
20
fa/code/src/apps/ch.2.3/variadic_functions/main.go
Normal file
20
fa/code/src/apps/ch.2.3/variadic_functions/main.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Example code for Chapter 2.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to return multiple values from a function
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// return results of A + B and A * B
|
||||
func SumAndProduct(A, B int) (int, int) {
|
||||
return A + B, A * B
|
||||
}
|
||||
|
||||
func main() {
|
||||
x := 3
|
||||
y := 4
|
||||
|
||||
xPLUSy, xTIMESy := SumAndProduct(x, y)
|
||||
|
||||
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
|
||||
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
|
||||
}
|
||||
43
fa/code/src/apps/ch.2.4/compare_age/main.go
Normal file
43
fa/code/src/apps/ch.2.4/compare_age/main.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Example code for Chapter 2.4 from "Build Web Application with Golang"
|
||||
// Purpose: Shows you how to pass and use structs.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// define a new type
|
||||
type person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
// compare age of two people, return the older person and differences of age
|
||||
// struct is passed by value
|
||||
func Older(p1, p2 person) (person, int) {
|
||||
if p1.age > p2.age {
|
||||
return p1, p1.age - p2.age
|
||||
}
|
||||
return p2, p2.age - p1.age
|
||||
}
|
||||
|
||||
func main() {
|
||||
var tom person
|
||||
|
||||
// initialization
|
||||
tom.name, tom.age = "Tom", 18
|
||||
|
||||
// initialize two values by format "field:value"
|
||||
bob := person{age: 25, name: "Bob"}
|
||||
|
||||
// initialize two values with order
|
||||
paul := person{"Paul", 43}
|
||||
|
||||
tb_Older, tb_diff := Older(tom, bob)
|
||||
tp_Older, tp_diff := Older(tom, paul)
|
||||
bp_Older, bp_diff := Older(bob, paul)
|
||||
|
||||
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)
|
||||
|
||||
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)
|
||||
|
||||
fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/embedded_structs/main.go
Normal file
39
fa/code/src/apps/ch.2.4/embedded_structs/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Example code for Chapter 2.4 from "Build Web Application with Golang"
|
||||
// Purpose: Example of embedded fields
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
weight int
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human // anonymous field, it means Student struct includes all fields that Human has.
|
||||
speciality string
|
||||
}
|
||||
|
||||
func main() {
|
||||
// initialize a student
|
||||
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
|
||||
|
||||
// access fields
|
||||
fmt.Println("His name is ", mark.name)
|
||||
fmt.Println("His age is ", mark.age)
|
||||
fmt.Println("His weight is ", mark.weight)
|
||||
fmt.Println("His speciality is ", mark.speciality)
|
||||
// modify notes
|
||||
mark.speciality = "AI"
|
||||
fmt.Println("Mark changed his speciality")
|
||||
fmt.Println("His speciality is ", mark.speciality)
|
||||
// modify age
|
||||
fmt.Println("Mark become old")
|
||||
mark.age = 46
|
||||
fmt.Println("His age is", mark.age)
|
||||
// modify weight
|
||||
fmt.Println("Mark is not an athlete any more")
|
||||
mark.weight += 60
|
||||
fmt.Println("His weight is", mark.weight)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/embedded_structs2/main.go
Normal file
39
fa/code/src/apps/ch.2.4/embedded_structs2/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Example code for Chapter 2.4 from "Build Web Application with Golang"
|
||||
// Purpose: Another example of embedded fields
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Skills []string
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
weight int
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human // struct as embedded field
|
||||
Skills // string slice as embedded field
|
||||
int // built-in type as embedded field
|
||||
speciality string
|
||||
}
|
||||
|
||||
func main() {
|
||||
// initialize Student Jane
|
||||
jane := Student{Human: Human{"Jane", 35, 100}, speciality: "Biology"}
|
||||
// access fields
|
||||
fmt.Println("Her name is ", jane.name)
|
||||
fmt.Println("Her age is ", jane.age)
|
||||
fmt.Println("Her weight is ", jane.weight)
|
||||
fmt.Println("Her speciality is ", jane.speciality)
|
||||
// modify value of skill field
|
||||
jane.Skills = []string{"anatomy"}
|
||||
fmt.Println("Her skills are ", jane.Skills)
|
||||
fmt.Println("She acquired two new ones ")
|
||||
jane.Skills = append(jane.Skills, "physics", "golang")
|
||||
fmt.Println("Her skills now are ", jane.Skills)
|
||||
// modify embedded field
|
||||
jane.int = 3
|
||||
fmt.Println("Her preferred number is", jane.int)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Example code for Chapter 2.4 from "Build Web Application with Golang"
|
||||
// Purpose: Shows a name conflict with a embedded field
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string // Human has phone field
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human // embedded field Human
|
||||
speciality string
|
||||
phone string // phone in employee
|
||||
}
|
||||
|
||||
func main() {
|
||||
Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
|
||||
fmt.Println("Bob's work phone is:", Bob.phone)
|
||||
// access phone field in Human
|
||||
fmt.Println("Bob's personal phone is:", Bob.Human.phone)
|
||||
}
|
||||
39
fa/code/src/apps/ch.2.4/main.go
Normal file
39
fa/code/src/apps/ch.2.4/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Example code for Chapter 2.4 from "Build Web Application with Golang"
|
||||
// Purpose: Shows different ways of creating a struct
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func show_basic_struct() {
|
||||
fmt.Println("\nshow_basic_struct()")
|
||||
type person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
var P person // p is person type
|
||||
|
||||
P.name = "Astaxie" // assign "Astaxie" to the filed 'name' of p
|
||||
P.age = 25 // assign 25 to field 'age' of p
|
||||
fmt.Printf("The person's name is %s\n", P.name) // access field 'name' of p
|
||||
|
||||
tom := person{"Tom", 25}
|
||||
|
||||
bob := person{age: 24, name: "Bob"}
|
||||
|
||||
fmt.Printf("tom = %+v\n", tom)
|
||||
fmt.Printf("bob = %#v\n", bob)
|
||||
}
|
||||
func show_anonymous_struct() {
|
||||
fmt.Println("\nshow_anonymous_struct()")
|
||||
fmt.Printf("Anonymous struct = %#v\n", struct {
|
||||
name string
|
||||
count int
|
||||
}{
|
||||
"counter", 1,
|
||||
})
|
||||
}
|
||||
func main() {
|
||||
show_basic_struct()
|
||||
show_anonymous_struct()
|
||||
}
|
||||
36
fa/code/src/apps/ch.2.5/attach_methods_to_struct/main.go
Normal file
36
fa/code/src/apps/ch.2.5/attach_methods_to_struct/main.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Example code from Chapter 2.5
|
||||
// Attach method to struct.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Rectangle struct {
|
||||
width, height float64
|
||||
}
|
||||
|
||||
type Circle struct {
|
||||
radius float64
|
||||
}
|
||||
|
||||
func (r Rectangle) area() float64 {
|
||||
return r.width * r.height
|
||||
}
|
||||
|
||||
func (c Circle) area() float64 {
|
||||
return c.radius * c.radius * math.Pi
|
||||
}
|
||||
|
||||
func main() {
|
||||
r1 := Rectangle{12, 2}
|
||||
r2 := Rectangle{9, 4}
|
||||
c1 := Circle{10}
|
||||
c2 := Circle{25}
|
||||
|
||||
fmt.Println("Area of r1 is: ", r1.area())
|
||||
fmt.Println("Area of r2 is: ", r2.area())
|
||||
fmt.Println("Area of c1 is: ", c1.area())
|
||||
fmt.Println("Area of c2 is: ", c2.area())
|
||||
}
|
||||
73
fa/code/src/apps/ch.2.5/box_example/main.go
Normal file
73
fa/code/src/apps/ch.2.5/box_example/main.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
WHITE = iota
|
||||
BLACK
|
||||
BLUE
|
||||
RED
|
||||
YELLOW
|
||||
)
|
||||
|
||||
type Color byte
|
||||
|
||||
type Box struct {
|
||||
width, height, depth float64
|
||||
color Color
|
||||
}
|
||||
|
||||
type BoxList []Box //a slice of boxes
|
||||
|
||||
func (b Box) Volume() float64 {
|
||||
return b.width * b.height * b.depth
|
||||
}
|
||||
|
||||
func (b *Box) SetColor(c Color) {
|
||||
b.color = c
|
||||
}
|
||||
|
||||
func (bl BoxList) BiggestsColor() Color {
|
||||
v := 0.00
|
||||
k := Color(WHITE)
|
||||
for _, b := range bl {
|
||||
if b.Volume() > v {
|
||||
v = b.Volume()
|
||||
k = b.color
|
||||
}
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func (bl BoxList) PaintItBlack() {
|
||||
for i, _ := range bl {
|
||||
bl[i].SetColor(BLACK)
|
||||
}
|
||||
}
|
||||
|
||||
func (c Color) String() string {
|
||||
strings := []string{"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
|
||||
return strings[c]
|
||||
}
|
||||
|
||||
func main() {
|
||||
boxes := BoxList{
|
||||
Box{4, 4, 4, RED},
|
||||
Box{10, 10, 1, YELLOW},
|
||||
Box{1, 1, 20, BLACK},
|
||||
Box{10, 10, 1, BLUE},
|
||||
Box{10, 30, 1, WHITE},
|
||||
Box{20, 20, 20, YELLOW},
|
||||
}
|
||||
|
||||
fmt.Printf("We have %d boxes in our set\n", len(boxes))
|
||||
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
|
||||
fmt.Println("The color of the last one is", boxes[len(boxes)-1].color.String())
|
||||
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
|
||||
|
||||
fmt.Println("Let's paint them all black")
|
||||
boxes.PaintItBlack()
|
||||
fmt.Println("The color of the second one is", boxes[1].color.String())
|
||||
|
||||
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
|
||||
}
|
||||
31
fa/code/src/apps/ch.2.5/embedded_method/main.go
Normal file
31
fa/code/src/apps/ch.2.5/embedded_method/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
import "fmt"
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human // anonymous field
|
||||
school string
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human
|
||||
company string
|
||||
}
|
||||
|
||||
// define a method in Human
|
||||
func (h *Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
|
||||
mark.SayHi()
|
||||
sam.SayHi()
|
||||
}
|
||||
36
fa/code/src/apps/ch.2.5/method_overload/main.go
Normal file
36
fa/code/src/apps/ch.2.5/method_overload/main.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human
|
||||
school string
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human
|
||||
company string
|
||||
}
|
||||
|
||||
func (h *Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
}
|
||||
|
||||
func (e *Employee) SayHi() {
|
||||
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
||||
e.company, e.phone) //Yes you can split into 2 lines here.
|
||||
}
|
||||
|
||||
func main() {
|
||||
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
|
||||
mark.SayHi()
|
||||
sam.SayHi()
|
||||
}
|
||||
18
fa/code/src/apps/ch.2.5/pass_struct_to_method/main.go
Normal file
18
fa/code/src/apps/ch.2.5/pass_struct_to_method/main.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Rectangle struct {
|
||||
width, height float64
|
||||
}
|
||||
|
||||
func area(r Rectangle) float64 {
|
||||
return r.width * r.height
|
||||
}
|
||||
|
||||
func main() {
|
||||
r1 := Rectangle{12, 2}
|
||||
r2 := Rectangle{9, 4}
|
||||
fmt.Println("Area of r1 is: ", area(r1))
|
||||
fmt.Println("Area of r2 is: ", area(r2))
|
||||
}
|
||||
71
fa/code/src/apps/ch.2.6/interface/main.go
Normal file
71
fa/code/src/apps/ch.2.6/interface/main.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package main
|
||||
import "fmt"
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human
|
||||
school string
|
||||
loan float32
|
||||
}
|
||||
|
||||
type Employee struct {
|
||||
Human
|
||||
company string
|
||||
money float32
|
||||
}
|
||||
|
||||
func (h Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
}
|
||||
|
||||
func (h Human) Sing(lyrics string) {
|
||||
fmt.Println("La la la la...", lyrics)
|
||||
}
|
||||
|
||||
func (e Employee) SayHi() {
|
||||
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
||||
e.company, e.phone) //Yes you can split into 2 lines here.
|
||||
}
|
||||
|
||||
// Interface Men implemented by Human, Student and Employee
|
||||
type Men interface {
|
||||
SayHi()
|
||||
Sing(lyrics string)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
|
||||
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
|
||||
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||
Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||
|
||||
// define interface i
|
||||
var i Men
|
||||
|
||||
//i can store Student
|
||||
i = mike
|
||||
fmt.Println("This is Mike, a Student:")
|
||||
i.SayHi()
|
||||
i.Sing("November rain")
|
||||
|
||||
//i can store Employee
|
||||
i = Tom
|
||||
fmt.Println("This is Tom, an Employee:")
|
||||
i.SayHi()
|
||||
i.Sing("Born to be wild")
|
||||
|
||||
// slice of Men
|
||||
fmt.Println("Let's use a slice of Men and see what happens")
|
||||
x := make([]Men, 3)
|
||||
// these three elements are different types but they all implemented interface Men
|
||||
x[0], x[1], x[2] = paul, sam, mike
|
||||
|
||||
for _, value := range x{
|
||||
value.SayHi()
|
||||
}
|
||||
}
|
||||
33
fa/code/src/apps/ch.2.6/reflection/main.go
Normal file
33
fa/code/src/apps/ch.2.6/reflection/main.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func show_interface_none() {
|
||||
fmt.Println("\nshow_interface_none()")
|
||||
var a interface{}
|
||||
a = "string"
|
||||
a = 1
|
||||
a = false
|
||||
fmt.Println("a =", a)
|
||||
}
|
||||
func show_reflection() {
|
||||
fmt.Println("\nshow_reflection()")
|
||||
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())
|
||||
|
||||
p := reflect.ValueOf(&x)
|
||||
newX := p.Elem()
|
||||
newX.SetFloat(7.1)
|
||||
fmt.Println("newX =", newX)
|
||||
fmt.Println("newX float64() value:", newX.Float())
|
||||
}
|
||||
func main() {
|
||||
show_interface_none()
|
||||
show_reflection()
|
||||
}
|
||||
22
fa/code/src/apps/ch.2.6/stringer_interface/main.go
Normal file
22
fa/code/src/apps/ch.2.6/stringer_interface/main.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Human struct {
|
||||
name string
|
||||
age int
|
||||
phone string
|
||||
}
|
||||
|
||||
// Human implemented fmt.Stringer
|
||||
func (h Human) String() string {
|
||||
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
|
||||
}
|
||||
|
||||
func main() {
|
||||
Bob := Human{"Bob", 39, "000-7777-XXX"}
|
||||
fmt.Println("This Human is : ", Bob)
|
||||
}
|
||||
38
fa/code/src/apps/ch.2.6/switch_type_check/main.go
Normal file
38
fa/code/src/apps/ch.2.6/switch_type_check/main.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
|
||||
type Person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 //an int
|
||||
list[1] = "Hello" //a string
|
||||
list[2] = Person{"Dennis", 70}
|
||||
|
||||
for index, element := range list {
|
||||
switch value := element.(type) {
|
||||
case int:
|
||||
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||
case string:
|
||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||
case Person:
|
||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||
default:
|
||||
fmt.Println("list[%d] is of a different type", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
37
fa/code/src/apps/ch.2.6/type_check/main.go
Normal file
37
fa/code/src/apps/ch.2.6/type_check/main.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Element interface{}
|
||||
type List []Element
|
||||
|
||||
type Person struct {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||
}
|
||||
|
||||
func main() {
|
||||
list := make(List, 3)
|
||||
list[0] = 1 // an int
|
||||
list[1] = "Hello" // a string
|
||||
list[2] = Person{"Dennis", 70}
|
||||
|
||||
for index, element := range list {
|
||||
if value, ok := element.(int); ok {
|
||||
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||
} else if value, ok := element.(string); ok {
|
||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||
} else if value, ok := element.(Person); ok {
|
||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||
} else {
|
||||
fmt.Println("list[%d] is of a different type", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
13
fa/code/src/apps/ch.2.7/buffered_channel/main.go
Normal file
13
fa/code/src/apps/ch.2.7/buffered_channel/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to use a buffered channel
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 2) // change 2 to 1 will have runtime error, but 3 is fine
|
||||
c <- 1
|
||||
c <- 2
|
||||
fmt.Println(<-c)
|
||||
fmt.Println(<-c)
|
||||
}
|
||||
20
fa/code/src/apps/ch.2.7/goroutine/main.go
Normal file
20
fa/code/src/apps/ch.2.7/goroutine/main.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to launch a simple gorountine
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func say(s string) {
|
||||
for i := 0; i < 5; i++ {
|
||||
runtime.Gosched()
|
||||
fmt.Println(s)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
go say("world") // create a new goroutine
|
||||
say("hello") // current goroutine
|
||||
}
|
||||
24
fa/code/src/apps/ch.2.7/range_and_close_channel/main.go
Normal file
24
fa/code/src/apps/ch.2.7/range_and_close_channel/main.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to close and interate through a channel
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func fibonacci(n int, c chan int) {
|
||||
x, y := 1, 1
|
||||
for i := 0; i < n; i++ {
|
||||
c <- x
|
||||
x, y = y, x+y
|
||||
}
|
||||
close(c)
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 10)
|
||||
go fibonacci(cap(c), c)
|
||||
for i := range c {
|
||||
fmt.Println(i)
|
||||
}
|
||||
}
|
||||
30
fa/code/src/apps/ch.2.7/select_channel/main.go
Normal file
30
fa/code/src/apps/ch.2.7/select_channel/main.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to use `select`
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func fibonacci(c, quit chan int) {
|
||||
x, y := 1, 1
|
||||
for {
|
||||
select {
|
||||
case c <- x:
|
||||
x, y = y, x+y
|
||||
case <-quit:
|
||||
fmt.Println("quit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int)
|
||||
quit := make(chan int)
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Println(<-c)
|
||||
}
|
||||
quit <- 0
|
||||
}()
|
||||
fibonacci(c, quit)
|
||||
}
|
||||
27
fa/code/src/apps/ch.2.7/timeout/main.go
Normal file
27
fa/code/src/apps/ch.2.7/timeout/main.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to create and use a timeout
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
func main() {
|
||||
c := make(chan int)
|
||||
o := make(chan bool)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case v := <-c:
|
||||
fmt.Println(v)
|
||||
case <-time.After(5 * time.Second):
|
||||
fmt.Println("timeout")
|
||||
o <- true
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
<-o
|
||||
}
|
||||
24
fa/code/src/apps/ch.2.7/unbuffered_channel/main.go
Normal file
24
fa/code/src/apps/ch.2.7/unbuffered_channel/main.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Example code for Chapter 2.7 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to create and use a unbuffered channel
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func sum(a []int, c chan int) {
|
||||
total := 0
|
||||
for _, v := range a {
|
||||
total += v
|
||||
}
|
||||
c <- total // send total to c
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := []int{7, 2, 8, -9, 4, 0}
|
||||
|
||||
c := make(chan int)
|
||||
go sum(a[:len(a)/2], c)
|
||||
go sum(a[len(a)/2:], c)
|
||||
x, y := <-c, <-c // receive from c
|
||||
|
||||
fmt.Println(x, y, x+y)
|
||||
}
|
||||
31
fa/code/src/apps/ch.3.2/main.go
Normal file
31
fa/code/src/apps/ch.3.2/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Example code for Chapter 3.2 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to acces the form values from the request
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm() // parse arguments, you have to call this by yourself
|
||||
fmt.Println(r.Form) // print form information in server side
|
||||
fmt.Println("path", r.URL.Path)
|
||||
fmt.Println("scheme", r.URL.Scheme)
|
||||
fmt.Println(r.Form["url_long"])
|
||||
for k, v := range r.Form {
|
||||
fmt.Println("key:", k)
|
||||
fmt.Println("val:", strings.Join(v, ""))
|
||||
}
|
||||
fmt.Fprintf(w, "Hello astaxie!") // send data to client side
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", sayhelloName) // set router
|
||||
err := http.ListenAndServe(":9090", nil) // set listen port
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
30
fa/code/src/apps/ch.3.4/main.go
Normal file
30
fa/code/src/apps/ch.3.4/main.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Example code for Chapter 3.4 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to create a handler for `http.ListenAndServe()`
|
||||
// Run `go run main.go` then access `http://localhost:9090`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MyMux struct {
|
||||
}
|
||||
|
||||
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
sayhelloName(w, r)
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello myroute!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := &MyMux{}
|
||||
http.ListenAndServe(":9090", mux)
|
||||
}
|
||||
12
fa/code/src/apps/ch.4.1/login.gtpl
Normal file
12
fa/code/src/apps/ch.4.1/login.gtpl
Normal file
@@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/login" method="post">
|
||||
Username:<input type="text" name="username">
|
||||
Password:<input type="password" name="password">
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
48
fa/code/src/apps/ch.4.1/main.go
Normal file
48
fa/code/src/apps/ch.4.1/main.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Example code for Chapter 4.1 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to create a simple login using a template
|
||||
// Run: `go run main.go`, then access `http://localhost:9090` and `http://localhost:9090/login`
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm() //Parse url parameters passed, then parse the response packet for the POST body (request body)
|
||||
// attention: If you do not call ParseForm method, the following data can not be obtained form
|
||||
fmt.Println(r.Form) // print information on server side.
|
||||
fmt.Println("path", r.URL.Path)
|
||||
fmt.Println("scheme", r.URL.Scheme)
|
||||
fmt.Println(r.Form["url_long"])
|
||||
for k, v := range r.Form {
|
||||
fmt.Println("key:", k)
|
||||
fmt.Println("val:", strings.Join(v, ""))
|
||||
}
|
||||
fmt.Fprintf(w, "Hello astaxie!") // write data to response
|
||||
}
|
||||
|
||||
func login(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("method:", r.Method) //get request method
|
||||
if r.Method == "GET" {
|
||||
t, _ := template.ParseFiles("login.gtpl")
|
||||
t.Execute(w, nil)
|
||||
} else {
|
||||
r.ParseForm()
|
||||
// logic part of log in
|
||||
fmt.Println("username:", r.Form["username"])
|
||||
fmt.Println("password:", r.Form["password"])
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", sayhelloName) // setting router rule
|
||||
http.HandleFunc("/login", login)
|
||||
err := http.ListenAndServe(":9090", nil) // setting listening port
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
59
fa/code/src/apps/ch.4.2/main.go
Normal file
59
fa/code/src/apps/ch.4.2/main.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Example code for Chapter 4.2 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to perform server-side validation of user input from a form.
|
||||
// Also shows to use multiple template files with predefined template names.
|
||||
// Run `go run main.go` and then access http://localhost:9090
|
||||
package main
|
||||
|
||||
import (
|
||||
"apps/ch.4.2/validator"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
PORT = "9090"
|
||||
HOST_URL = "http://localhost:" + PORT
|
||||
)
|
||||
|
||||
var t *template.Template
|
||||
|
||||
type Links struct {
|
||||
BadLinks [][2]string
|
||||
}
|
||||
|
||||
// invalid links to display for testing.
|
||||
var links Links
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, HOST_URL+"/profile", http.StatusTemporaryRedirect)
|
||||
}
|
||||
func profileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
t.ExecuteTemplate(w, "profile", links)
|
||||
}
|
||||
func checkProfile(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
p := validator.ProfilePage{&r.Form}
|
||||
t.ExecuteTemplate(w, "submission", p.GetErrors())
|
||||
}
|
||||
|
||||
// This function is called before main()
|
||||
func init() {
|
||||
// Note: we can reference the loaded templates by their defined name inside the template files.
|
||||
t = template.Must(template.ParseFiles("profile.gtpl", "submission.gtpl"))
|
||||
|
||||
list := make([][2]string, 2)
|
||||
list[0] = [2]string{HOST_URL + "/checkprofile", "No data"}
|
||||
list[1] = [2]string{HOST_URL + "/checkprofile?age=1&gender=guy&shirtsize=big", "Invalid options"}
|
||||
links = Links{list}
|
||||
}
|
||||
func main() {
|
||||
http.HandleFunc("/", index)
|
||||
http.HandleFunc("/profile", profileHandler)
|
||||
http.HandleFunc("/checkprofile", checkProfile)
|
||||
|
||||
err := http.ListenAndServe(":"+PORT, nil) // setting listening port
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
89
fa/code/src/apps/ch.4.2/profile.gtpl
Normal file
89
fa/code/src/apps/ch.4.2/profile.gtpl
Normal file
@@ -0,0 +1,89 @@
|
||||
{{define "profile"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
.row{
|
||||
display: table-row;
|
||||
}
|
||||
.cell{
|
||||
display: table-cell;
|
||||
}
|
||||
.required{
|
||||
color: red
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h2>Profile Setup:</h2>
|
||||
<form action="/checkprofile">
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>User Name:</div>
|
||||
<div class="cell"><input type="text" name="username" id="username" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Age:</div>
|
||||
<div class="cell"><input type="number" min="13" max="130" name="age" id="age" size="3" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Email:</div>
|
||||
<div class="cell"><input type="email" name="email" id="email" placeholder="john@example.com" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Birth day:</div>
|
||||
<div class="cell">
|
||||
<input type="date" name="birthday" id="birthday" placeholder="MM/DD/YYYY" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Gender:</div>
|
||||
<div class="cell">
|
||||
<label for="gender_male">
|
||||
Male: <input type="radio" name="gender" value="m" id="gender_male"/>
|
||||
</label>
|
||||
<label for="gender_female">
|
||||
Female: <input type="radio" name="gender" value="f" id="gender_female"/>
|
||||
</label>
|
||||
<label for="gender_na">
|
||||
N/A: <input type="radio" name="gender" value="na" id="gender_na"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Siblings:</div>
|
||||
<div class="cell">
|
||||
<label for="sibling_male">
|
||||
Brother: <input type="checkbox" name="sibling" value="m" id="sibling_male"/>
|
||||
</label>
|
||||
<label for="sibling_female">
|
||||
Sister: <input type="checkbox" name="sibling" value="f" id="sibling_female"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Shirt Size:</div>
|
||||
<div class="cell">
|
||||
<select id="shirt_size" >
|
||||
<option></option>
|
||||
<option value="s">Small</option>
|
||||
<option value="m">Medium</option>
|
||||
<option value="l">Large</option>
|
||||
<option value="xl">X-Large</option>
|
||||
<option value="xxl">XX-Large</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Chinese Name:</div>
|
||||
<div class="cell"><input type="text" name="chineseName" id="chineseName"/></div>
|
||||
</div>
|
||||
<br/>
|
||||
<span class="required">*</span>Required
|
||||
<br/>
|
||||
<input type="submit" value="Submit" id="submitBtn"/>
|
||||
</form>
|
||||
<h2>Invalid submissions</h2>
|
||||
<ol>{{range .BadLinks}}
|
||||
<li><a href="{{index . 0}}">{{index . 1}}</a></li>
|
||||
{{end}}
|
||||
</ol>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
16
fa/code/src/apps/ch.4.2/submission.gtpl
Normal file
16
fa/code/src/apps/ch.4.2/submission.gtpl
Normal file
@@ -0,0 +1,16 @@
|
||||
{{define "submission"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
{{if .Errors}}
|
||||
<h2>Errors:</h2>
|
||||
<ol>
|
||||
{{range .Errors}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
{{else}}
|
||||
Profile successfully submitted.
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
175
fa/code/src/apps/ch.4.2/validator/main.go
Normal file
175
fa/code/src/apps/ch.4.2/validator/main.go
Normal file
@@ -0,0 +1,175 @@
|
||||
// This file contains all the validators to validate the profile page.
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProfilePage struct {
|
||||
Form *url.Values
|
||||
}
|
||||
type Errors struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
// Goes through the form object and validates each element.
|
||||
// Attachs an error to the output if validation fails.
|
||||
func (p *ProfilePage) GetErrors() Errors {
|
||||
errs := make([]error, 0, 10)
|
||||
if *p.Form == nil || len(*p.Form) < 1 {
|
||||
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
|
||||
}
|
||||
for name, val := range *p.Form {
|
||||
if fn, ok := stringValidator[name]; ok {
|
||||
if err := fn(strings.Join(val, "")); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
} else {
|
||||
if fn, ok := stringsValidator[name]; ok {
|
||||
if err := fn(val); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Errors{errs}
|
||||
}
|
||||
|
||||
const (
|
||||
// Used for parsing the time
|
||||
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
|
||||
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
|
||||
)
|
||||
|
||||
var stringValidator map[string]func(string) error = map[string]func(string) error{
|
||||
// parameter name : validator reference
|
||||
"age": checkAge,
|
||||
"birthday": checkDate,
|
||||
"chineseName": checkChineseName,
|
||||
"email": checkEmail,
|
||||
"gender": checkGender,
|
||||
"shirtsize": checkShirtSize,
|
||||
"username": checkUsername,
|
||||
}
|
||||
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
|
||||
// parameter name : validator reference
|
||||
"sibling": checkSibling,
|
||||
}
|
||||
|
||||
// Returns true if slices have a common element
|
||||
func doSlicesIntersect(s1, s2 []string) bool {
|
||||
if s1 == nil || s2 == nil {
|
||||
return false
|
||||
}
|
||||
for _, str := range s1 {
|
||||
if isElementInSlice(str, s2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func isElementInSlice(str string, sl []string) bool {
|
||||
if sl == nil || str == "" {
|
||||
return false
|
||||
}
|
||||
for _, v := range sl {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks if all the characters are chinese characters. Won't check if empty.'
|
||||
func checkChineseName(str string) error {
|
||||
if str != "" {
|
||||
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
|
||||
return errors.New("Please make sure that the chinese name only contains chinese characters.")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a user name exist.
|
||||
func checkUsername(str string) error {
|
||||
if strings.Trim(str, " ") == "" {
|
||||
return errors.New("Please enter a username.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if age is a number and between 13 and 130
|
||||
func checkAge(str string) error {
|
||||
age, err := strconv.Atoi(str)
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid age.")
|
||||
}
|
||||
if age < 13 {
|
||||
return errors.New("You must be at least 13 years of age to submit.")
|
||||
}
|
||||
if age > 130 {
|
||||
return errors.New("You're too old to register, grandpa.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func checkEmail(str string) error {
|
||||
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
|
||||
fmt.Println("err = ", err)
|
||||
return errors.New("Please enter a valid email address.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a valid date was passed.
|
||||
func checkDate(str string) error {
|
||||
_, err := time.Parse(mmddyyyyForm, str)
|
||||
if err != nil {
|
||||
_, err = time.Parse(yyyymmddForm, str)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid Date.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the passed input is a known gender option
|
||||
func checkGender(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f", "na"}
|
||||
if !isElementInSlice(str, siblings) {
|
||||
return errors.New("Please select a valid gender.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if all the values are known options.
|
||||
func checkSibling(strs []string) error {
|
||||
if strs == nil || len(strs) < 1 {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f"}
|
||||
if siblings != nil && !doSlicesIntersect(siblings, strs) {
|
||||
return errors.New("Please select a valid sibling")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the shirt size is a known option.
|
||||
func checkShirtSize(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
shirts := []string{"s", "m", "l", "xl", "xxl"}
|
||||
if !isElementInSlice(str, shirts) {
|
||||
return errors.New("Please select a valid shirt size")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
28
fa/code/src/apps/ch.4.3/index.gtpl
Normal file
28
fa/code/src/apps/ch.4.3/index.gtpl
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<h2>Cross Site Scripting Attack Test</h2>
|
||||
{{if .}}
|
||||
Previous User Input: <br/>
|
||||
|
||||
<code><pre>{{.}}</pre></code>
|
||||
{{end}}
|
||||
<form action="/">
|
||||
<label>
|
||||
User Input:
|
||||
<input type="text" size=50 name="userinput" id="userinput"/>
|
||||
</label>
|
||||
<br/>
|
||||
<label>
|
||||
Escape Input:
|
||||
<input type="checkbox" value="1" name="escape" id="escape"/>
|
||||
</label>
|
||||
<br/>
|
||||
<input type="submit" id="submitBtn" value="Submit"/>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
var s = "<scri"+"pt>alert('pOwned by XSS.')</scri"+"pt>"
|
||||
document.getElementById("userinput").value = s;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
fa/code/src/apps/ch.4.3/main.go
Normal file
39
fa/code/src/apps/ch.4.3/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Example code for Chapter 4.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to properly escape input
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
textTemplate "text/template"
|
||||
)
|
||||
|
||||
var t *template.Template = template.Must(template.ParseFiles("index.gtpl"))
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
userInput := r.Form.Get("userinput")
|
||||
if 0 < len(r.Form.Get("escape")) {
|
||||
t.Execute(w, template.HTMLEscapeString(userInput))
|
||||
} else {
|
||||
// Variables with type `template.HTML` are not escaped when passed to `.Execute()`
|
||||
t.Execute(w, template.HTML(userInput))
|
||||
}
|
||||
}
|
||||
func templateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
userInput := r.Form.Get("userinput")
|
||||
if 0 < len(r.Form.Get("escape")) {
|
||||
// `html/template.Execute()` escapes input
|
||||
t.Execute(w, userInput)
|
||||
} else {
|
||||
tt := textTemplate.Must(textTemplate.ParseFiles("index.gtpl"))
|
||||
// `text/template.Execute()` doesn't escape input
|
||||
tt.Execute(w, userInput)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
http.HandleFunc("/", index)
|
||||
http.HandleFunc("/template", templateHandler)
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
||||
54
fa/code/src/apps/ch.4.4/main.go
Normal file
54
fa/code/src/apps/ch.4.4/main.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Example code for Chapter 3.2 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to prevent duplicate submissions by using tokens
|
||||
// Example code for Chapter 4.4 based off the code from Chapter 4.2
|
||||
// Run `go run main.go` then access http://localhost:9090
|
||||
package main
|
||||
|
||||
import (
|
||||
"apps/ch.4.4/nonce"
|
||||
"apps/ch.4.4/validator"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
PORT = "9090"
|
||||
HOST_URL = "http://localhost:" + PORT
|
||||
)
|
||||
|
||||
var submissions nonce.Nonces
|
||||
var t *template.Template
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, HOST_URL+"/profile", http.StatusTemporaryRedirect)
|
||||
}
|
||||
func profileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
t.ExecuteTemplate(w, "profile", submissions.NewNonce())
|
||||
}
|
||||
func checkProfile(w http.ResponseWriter, r *http.Request) {
|
||||
var errs validator.Errors
|
||||
r.ParseForm()
|
||||
token := r.Form.Get("token")
|
||||
if err := submissions.CheckThenMarkToken(token); err != nil {
|
||||
errs = validator.Errors{[]error{err}}
|
||||
} else {
|
||||
p := validator.ProfilePage{&r.Form}
|
||||
errs = p.GetErrors()
|
||||
}
|
||||
t.ExecuteTemplate(w, "submission", errs)
|
||||
}
|
||||
func init() {
|
||||
submissions = nonce.New()
|
||||
t = template.Must(template.ParseFiles("profile.gtpl", "submission.gtpl"))
|
||||
}
|
||||
func main() {
|
||||
http.HandleFunc("/", index)
|
||||
http.HandleFunc("/profile", profileHandler)
|
||||
http.HandleFunc("/checkprofile", checkProfile)
|
||||
|
||||
err := http.ListenAndServe(":"+PORT, nil) // setting listening port
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
70
fa/code/src/apps/ch.4.4/nonce/main.go
Normal file
70
fa/code/src/apps/ch.4.4/nonce/main.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// A nonce is a number or string used only once.
|
||||
// This is useful for generating a unique token for login pages to prevent duplicate submissions.
|
||||
package nonce
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Contains a unique token
|
||||
type Nonce struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
// Keeps track of marked/used tokens
|
||||
type Nonces struct {
|
||||
hashs map[string]bool
|
||||
}
|
||||
|
||||
func New() Nonces {
|
||||
return Nonces{make(map[string]bool)}
|
||||
}
|
||||
func (n *Nonces) NewNonce() Nonce {
|
||||
return Nonce{n.NewToken()}
|
||||
}
|
||||
|
||||
// Returns a new unique token
|
||||
func (n *Nonces) NewToken() string {
|
||||
t := createToken()
|
||||
for n.HasToken(t) {
|
||||
t = createToken()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Checks if token has been marked.
|
||||
func (n *Nonces) HasToken(token string) bool {
|
||||
return n.hashs[token] == true
|
||||
}
|
||||
func (n *Nonces) MarkToken(token string) {
|
||||
n.hashs[token] = true
|
||||
}
|
||||
func (n *Nonces) CheckToken(token string) error {
|
||||
if token == "" {
|
||||
return errors.New("No token supplied")
|
||||
}
|
||||
if n.HasToken(token) {
|
||||
return errors.New("Duplicate submission.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (n *Nonces) CheckThenMarkToken(token string) error {
|
||||
defer n.MarkToken(token)
|
||||
if err := n.CheckToken(token); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func createToken() string {
|
||||
h := md5.New()
|
||||
now := time.Now().Unix()
|
||||
io.WriteString(h, strconv.FormatInt(now, 10))
|
||||
io.WriteString(h, strconv.FormatInt(rand.Int63(), 10))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
85
fa/code/src/apps/ch.4.4/profile.gtpl
Normal file
85
fa/code/src/apps/ch.4.4/profile.gtpl
Normal file
@@ -0,0 +1,85 @@
|
||||
{{define "profile"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
.row{
|
||||
display: table-row;
|
||||
}
|
||||
.cell{
|
||||
display: table-cell;
|
||||
}
|
||||
.required{
|
||||
color: red
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h2>Profile Setup:</h2>
|
||||
<form action="/checkprofile" method="POST">
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>User Name:</div>
|
||||
<div class="cell"><input type="text" name="username" id="username" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Age:</div>
|
||||
<div class="cell"><input type="number" min="13" max="130" name="age" id="age" size="3" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Email:</div>
|
||||
<div class="cell"><input type="email" name="email" id="email" placeholder="john@example.com" required/></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell"><span class="required">*</span>Birth day:</div>
|
||||
<div class="cell">
|
||||
<input type="date" name="birthday" id="birthday" placeholder="MM/DD/YYYY" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Gender:</div>
|
||||
<div class="cell">
|
||||
<label for="gender_male">
|
||||
Male: <input type="radio" name="gender" value="m" id="gender_male"/>
|
||||
</label>
|
||||
<label for="gender_female">
|
||||
Female: <input type="radio" name="gender" value="f" id="gender_female"/>
|
||||
</label>
|
||||
<label for="gender_na">
|
||||
N/A: <input type="radio" name="gender" value="na" id="gender_na"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Siblings:</div>
|
||||
<div class="cell">
|
||||
<label for="sibling_male">
|
||||
Brother: <input type="checkbox" name="sibling" value="m" id="sibling_male"/>
|
||||
</label>
|
||||
<label for="sibling_female">
|
||||
Sister: <input type="checkbox" name="sibling" value="f" id="sibling_female"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Shirt Size:</div>
|
||||
<div class="cell">
|
||||
<select id="shirt_size" >
|
||||
<option></option>
|
||||
<option value="s">Small</option>
|
||||
<option value="m">Medium</option>
|
||||
<option value="l">Large</option>
|
||||
<option value="xl">X-Large</option>
|
||||
<option value="xxl">XX-Large</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell">Chinese Name:</div>
|
||||
<div class="cell"><input type="text" name="chineseName" id="chineseName"/></div>
|
||||
</div>
|
||||
<br/>
|
||||
<span class="required">*</span>Required
|
||||
<br/>
|
||||
<input type="hidden" name="token" value="{{.Token}}"/>
|
||||
<input type="submit" value="Submit" id="submitBtn"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
17
fa/code/src/apps/ch.4.4/submission.gtpl
Normal file
17
fa/code/src/apps/ch.4.4/submission.gtpl
Normal file
@@ -0,0 +1,17 @@
|
||||
{{define "submission"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
{{if .Errors}}
|
||||
<h2>Errors:</h2>
|
||||
<ol>
|
||||
{{range .Errors}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
{{else}}
|
||||
Profile successfully submitted.<br/>
|
||||
Note: Refreshing the page will produce a duplicate entry.
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
175
fa/code/src/apps/ch.4.4/validator/main.go
Normal file
175
fa/code/src/apps/ch.4.4/validator/main.go
Normal file
@@ -0,0 +1,175 @@
|
||||
// This file contains all the validators to validate the profile page.
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProfilePage struct {
|
||||
Form *url.Values
|
||||
}
|
||||
type Errors struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
// Goes through the form object and validates each element.
|
||||
// Attachs an error to the output if validation fails.
|
||||
func (p *ProfilePage) GetErrors() Errors {
|
||||
errs := make([]error, 0, 10)
|
||||
if *p.Form == nil || len(*p.Form) < 1 {
|
||||
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
|
||||
}
|
||||
for name, val := range *p.Form {
|
||||
if fn, ok := stringValidator[name]; ok {
|
||||
if err := fn(strings.Join(val, "")); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
} else {
|
||||
if fn, ok := stringsValidator[name]; ok {
|
||||
if err := fn(val); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Errors{errs}
|
||||
}
|
||||
|
||||
const (
|
||||
// Used for parsing the time
|
||||
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
|
||||
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
|
||||
)
|
||||
|
||||
var stringValidator map[string]func(string) error = map[string]func(string) error{
|
||||
// parameter name : validator reference
|
||||
"age": checkAge,
|
||||
"birthday": checkDate,
|
||||
"chineseName": checkChineseName,
|
||||
"email": checkEmail,
|
||||
"gender": checkGender,
|
||||
"shirtsize": checkShirtSize,
|
||||
"username": checkUsername,
|
||||
}
|
||||
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
|
||||
// parameter name : validator reference
|
||||
"sibling": checkSibling,
|
||||
}
|
||||
|
||||
// Returns true if slices have a common element
|
||||
func doSlicesIntersect(s1, s2 []string) bool {
|
||||
if s1 == nil || s2 == nil {
|
||||
return false
|
||||
}
|
||||
for _, str := range s1 {
|
||||
if isElementInSlice(str, s2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func isElementInSlice(str string, sl []string) bool {
|
||||
if sl == nil || str == "" {
|
||||
return false
|
||||
}
|
||||
for _, v := range sl {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks if all the characters are chinese characters. Won't check if empty.'
|
||||
func checkChineseName(str string) error {
|
||||
if str != "" {
|
||||
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
|
||||
return errors.New("Please make sure that the chinese name only contains chinese characters.")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a user name exist.
|
||||
func checkUsername(str string) error {
|
||||
if strings.Trim(str, " ") == "" {
|
||||
return errors.New("Please enter a username.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if age is a number and between 13 and 130
|
||||
func checkAge(str string) error {
|
||||
age, err := strconv.Atoi(str)
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid age.")
|
||||
}
|
||||
if age < 13 {
|
||||
return errors.New("You must be at least 13 years of age to submit.")
|
||||
}
|
||||
if age > 130 {
|
||||
return errors.New("You're too old to register, grandpa.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func checkEmail(str string) error {
|
||||
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
|
||||
fmt.Println("err = ", err)
|
||||
return errors.New("Please enter a valid email address.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a valid date was passed.
|
||||
func checkDate(str string) error {
|
||||
_, err := time.Parse(mmddyyyyForm, str)
|
||||
if err != nil {
|
||||
_, err = time.Parse(yyyymmddForm, str)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid Date.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the passed input is a known gender option
|
||||
func checkGender(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f", "na"}
|
||||
if !isElementInSlice(str, siblings) {
|
||||
return errors.New("Please select a valid gender.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if all the values are known options.
|
||||
func checkSibling(strs []string) error {
|
||||
if strs == nil || len(strs) < 1 {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f"}
|
||||
if siblings != nil && !doSlicesIntersect(siblings, strs) {
|
||||
return errors.New("Please select a valid sibling")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the shirt size is a known option.
|
||||
func checkShirtSize(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
shirts := []string{"s", "m", "l", "xl", "xxl"}
|
||||
if !isElementInSlice(str, shirts) {
|
||||
return errors.New("Please select a valid shirt size")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
46
fa/code/src/apps/ch.4.5/client_upload/main.go
Normal file
46
fa/code/src/apps/ch.4.5/client_upload/main.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
func postFile(filename string, targetUrl string) {
|
||||
bodyBuf := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||
fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)
|
||||
checkError(err)
|
||||
|
||||
fh, err := os.Open(filename)
|
||||
checkError(err)
|
||||
|
||||
_, err = io.Copy(fileWriter, fh)
|
||||
checkError(err)
|
||||
|
||||
contentType := bodyWriter.FormDataContentType()
|
||||
bodyWriter.Close()
|
||||
resp, err := http.Post(targetUrl, contentType, bodyBuf)
|
||||
checkError(err)
|
||||
|
||||
defer resp.Body.Close()
|
||||
resp_body, err := ioutil.ReadAll(resp.Body)
|
||||
checkError(err)
|
||||
|
||||
fmt.Println(resp.Status)
|
||||
fmt.Println(string(resp_body))
|
||||
}
|
||||
func main() {
|
||||
target_url := "http://localhost:9090/upload"
|
||||
filename := "../file.txt"
|
||||
postFile(filename, target_url)
|
||||
}
|
||||
15
fa/code/src/apps/ch.4.5/index.gtpl
Normal file
15
fa/code/src/apps/ch.4.5/index.gtpl
Normal file
@@ -0,0 +1,15 @@
|
||||
{{define "index"}}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Upload file</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="http://127.0.0.1:9090/upload" method="post">
|
||||
<input type="file" name="uploadfile" />
|
||||
<input type="hidden" name="token" value="{{.}}"/>
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
64
fa/code/src/apps/ch.4.5/main.go
Normal file
64
fa/code/src/apps/ch.4.5/main.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Example code for Chapter 4.5
|
||||
// Purpose is to create a server to handle uploading files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"apps/ch.4.4/nonce"
|
||||
"apps/ch.4.4/validator"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
const MiB_UNIT = 1 << 20
|
||||
|
||||
var t *template.Template
|
||||
var submissions nonce.Nonces = nonce.New()
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := t.ExecuteTemplate(w, "index", submissions.NewToken())
|
||||
checkError(err)
|
||||
}
|
||||
func uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var errs validator.Errors
|
||||
r.ParseMultipartForm(32 * MiB_UNIT)
|
||||
token := r.Form.Get("token")
|
||||
if err := submissions.CheckThenMarkToken(token); err != nil {
|
||||
errs = validator.Errors{[]error{err}}
|
||||
} else {
|
||||
file, handler, err := r.FormFile("uploadfile")
|
||||
checkError(err)
|
||||
saveUpload(file, handler)
|
||||
}
|
||||
err := t.ExecuteTemplate(w, "upload", errs)
|
||||
checkError(err)
|
||||
}
|
||||
func saveUpload(file multipart.File, handler *multipart.FileHeader) {
|
||||
defer file.Close()
|
||||
fmt.Printf("Uploaded file info: %#v", handler.Header)
|
||||
localFilename := fmt.Sprintf("./uploads/%v.%v", handler.Filename, submissions.NewToken())
|
||||
f, err := os.OpenFile(localFilename, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
checkError(err)
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, file)
|
||||
checkError(err)
|
||||
}
|
||||
func init() {
|
||||
var err error
|
||||
t, err = template.ParseFiles("index.gtpl", "upload.gtpl")
|
||||
checkError(err)
|
||||
}
|
||||
func main() {
|
||||
http.HandleFunc("/", indexHandler)
|
||||
http.HandleFunc("/upload", uploadHandler)
|
||||
err := http.ListenAndServe(":9090", nil)
|
||||
checkError(err)
|
||||
}
|
||||
70
fa/code/src/apps/ch.4.5/nonce/main.go
Normal file
70
fa/code/src/apps/ch.4.5/nonce/main.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// A nonce is a number or string used only once.
|
||||
// This is useful for generating a unique token for login pages to prevent duplicate submissions.
|
||||
package nonce
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Contains a unique token
|
||||
type Nonce struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
// Keeps track of marked/used tokens
|
||||
type Nonces struct {
|
||||
hashs map[string]bool
|
||||
}
|
||||
|
||||
func New() Nonces {
|
||||
return Nonces{make(map[string]bool)}
|
||||
}
|
||||
func (n *Nonces) NewNonce() Nonce {
|
||||
return Nonce{n.NewToken()}
|
||||
}
|
||||
|
||||
// Returns a new unique token
|
||||
func (n *Nonces) NewToken() string {
|
||||
t := createToken()
|
||||
for n.HasToken(t) {
|
||||
t = createToken()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Checks if token has been marked.
|
||||
func (n *Nonces) HasToken(token string) bool {
|
||||
return n.hashs[token] == true
|
||||
}
|
||||
func (n *Nonces) MarkToken(token string) {
|
||||
n.hashs[token] = true
|
||||
}
|
||||
func (n *Nonces) CheckToken(token string) error {
|
||||
if token == "" {
|
||||
return errors.New("No token supplied")
|
||||
}
|
||||
if n.HasToken(token) {
|
||||
return errors.New("Duplicate submission.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (n *Nonces) CheckThenMarkToken(token string) error {
|
||||
defer n.MarkToken(token)
|
||||
if err := n.CheckToken(token); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func createToken() string {
|
||||
h := md5.New()
|
||||
now := time.Now().Unix()
|
||||
io.WriteString(h, strconv.FormatInt(now, 10))
|
||||
io.WriteString(h, strconv.FormatInt(rand.Int63(), 10))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
17
fa/code/src/apps/ch.4.5/upload.gtpl
Normal file
17
fa/code/src/apps/ch.4.5/upload.gtpl
Normal file
@@ -0,0 +1,17 @@
|
||||
{{define "upload"}}<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
{{if .Errors}}
|
||||
<h2>Errors:</h2>
|
||||
<ol>
|
||||
{{range .Errors}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ol>
|
||||
{{else}}
|
||||
File uploaded successfully.<br/>
|
||||
Note: Refreshing the page will produce a duplicate entry.
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
175
fa/code/src/apps/ch.4.5/validator/main.go
Normal file
175
fa/code/src/apps/ch.4.5/validator/main.go
Normal file
@@ -0,0 +1,175 @@
|
||||
// This file contains all the validators to validate the profile page.
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProfilePage struct {
|
||||
Form *url.Values
|
||||
}
|
||||
type Errors struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
// Goes through the form object and validates each element.
|
||||
// Attachs an error to the output if validation fails.
|
||||
func (p *ProfilePage) GetErrors() Errors {
|
||||
errs := make([]error, 0, 10)
|
||||
if *p.Form == nil || len(*p.Form) < 1 {
|
||||
errs = append(errs, errors.New("No data was received. Please submit from the profile page."))
|
||||
}
|
||||
for name, val := range *p.Form {
|
||||
if fn, ok := stringValidator[name]; ok {
|
||||
if err := fn(strings.Join(val, "")); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
} else {
|
||||
if fn, ok := stringsValidator[name]; ok {
|
||||
if err := fn(val); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Errors{errs}
|
||||
}
|
||||
|
||||
const (
|
||||
// Used for parsing the time
|
||||
mmddyyyyForm = "01/02/2006" // we want the date sent in this format
|
||||
yyyymmddForm = "2006-01-02" // However, HTML5 pages send the date in this format
|
||||
)
|
||||
|
||||
var stringValidator map[string]func(string) error = map[string]func(string) error{
|
||||
// parameter name : validator reference
|
||||
"age": checkAge,
|
||||
"birthday": checkDate,
|
||||
"chineseName": checkChineseName,
|
||||
"email": checkEmail,
|
||||
"gender": checkGender,
|
||||
"shirtsize": checkShirtSize,
|
||||
"username": checkUsername,
|
||||
}
|
||||
var stringsValidator map[string]func([]string) error = map[string]func([]string) error{
|
||||
// parameter name : validator reference
|
||||
"sibling": checkSibling,
|
||||
}
|
||||
|
||||
// Returns true if slices have a common element
|
||||
func doSlicesIntersect(s1, s2 []string) bool {
|
||||
if s1 == nil || s2 == nil {
|
||||
return false
|
||||
}
|
||||
for _, str := range s1 {
|
||||
if isElementInSlice(str, s2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func isElementInSlice(str string, sl []string) bool {
|
||||
if sl == nil || str == "" {
|
||||
return false
|
||||
}
|
||||
for _, v := range sl {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Checks if all the characters are chinese characters. Won't check if empty.'
|
||||
func checkChineseName(str string) error {
|
||||
if str != "" {
|
||||
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", strings.Trim(str, " ")); !m {
|
||||
return errors.New("Please make sure that the chinese name only contains chinese characters.")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a user name exist.
|
||||
func checkUsername(str string) error {
|
||||
if strings.Trim(str, " ") == "" {
|
||||
return errors.New("Please enter a username.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if age is a number and between 13 and 130
|
||||
func checkAge(str string) error {
|
||||
age, err := strconv.Atoi(str)
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid age.")
|
||||
}
|
||||
if age < 13 {
|
||||
return errors.New("You must be at least 13 years of age to submit.")
|
||||
}
|
||||
if age > 130 {
|
||||
return errors.New("You're too old to register, grandpa.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func checkEmail(str string) error {
|
||||
if m, err := regexp.MatchString(`^[^@]+@[^@]+$`, str); !m {
|
||||
fmt.Println("err = ", err)
|
||||
return errors.New("Please enter a valid email address.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if a valid date was passed.
|
||||
func checkDate(str string) error {
|
||||
_, err := time.Parse(mmddyyyyForm, str)
|
||||
if err != nil {
|
||||
_, err = time.Parse(yyyymmddForm, str)
|
||||
}
|
||||
if str == "" || err != nil {
|
||||
return errors.New("Please enter a valid Date.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the passed input is a known gender option
|
||||
func checkGender(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f", "na"}
|
||||
if !isElementInSlice(str, siblings) {
|
||||
return errors.New("Please select a valid gender.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if all the values are known options.
|
||||
func checkSibling(strs []string) error {
|
||||
if strs == nil || len(strs) < 1 {
|
||||
return nil
|
||||
}
|
||||
siblings := []string{"m", "f"}
|
||||
if siblings != nil && !doSlicesIntersect(siblings, strs) {
|
||||
return errors.New("Please select a valid sibling")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if the shirt size is a known option.
|
||||
func checkShirtSize(str string) error {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
shirts := []string{"s", "m", "l", "xl", "xxl"}
|
||||
if !isElementInSlice(str, shirts) {
|
||||
return errors.New("Please select a valid shirt size")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
76
fa/code/src/apps/ch.5.2/main.go
Normal file
76
fa/code/src/apps/ch.5.2/main.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Example code for Chapter 5.2 from "Build Web Application with Golang"
|
||||
// Purpose: Use SQL driver to perform simple CRUD operations.
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
const (
|
||||
DB_USER = "user"
|
||||
DB_PASSWORD = ""
|
||||
DB_NAME = "test"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dbSouce := fmt.Sprintf("%v:%v@/%v?charset=utf8", DB_USER, DB_PASSWORD, DB_NAME)
|
||||
db, err := sql.Open("mysql", dbSouce)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
|
||||
fmt.Println("Inserting")
|
||||
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "software developement", "2012-12-09")
|
||||
checkErr(err)
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println("id of last inserted row =", id)
|
||||
fmt.Println("Updating")
|
||||
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
|
||||
fmt.Println("Querying")
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username, department, created string
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println("uid | username | department | created")
|
||||
fmt.Printf("%3v | %6v | %6v | %6v\n", uid, username, department, created)
|
||||
}
|
||||
|
||||
fmt.Println("Deleting")
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
12
fa/code/src/apps/ch.5.2/readme.md
Normal file
12
fa/code/src/apps/ch.5.2/readme.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## Setup for `ch.5.2`
|
||||
|
||||
- Step 1) Install and run MySql
|
||||
- Step 2) Create a user and database according to the constants in `main.go`
|
||||
|
||||
DB_USER = "user"
|
||||
DB_PASSWORD = ""
|
||||
DB_NAME = "test"
|
||||
|
||||
- Step 3) Create table `userinfo` located at `schema.sql`
|
||||
- Step 4) Run `go get` to download and install the remote packages.
|
||||
- Step 5) Execute the program with `go run main.go`
|
||||
7
fa/code/src/apps/ch.5.2/schema.sql
Normal file
7
fa/code/src/apps/ch.5.2/schema.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INT(10) NOT NULL AUTO_INCREMENT,
|
||||
`username` VARCHAR(64) NULL DEFAULT NULL,
|
||||
`departname` VARCHAR(64) NULL DEFAULT NULL,
|
||||
`created` DATE NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`uid`)
|
||||
);
|
||||
BIN
fa/code/src/apps/ch.5.3/foo.db
Normal file
BIN
fa/code/src/apps/ch.5.3/foo.db
Normal file
Binary file not shown.
72
fa/code/src/apps/ch.5.3/main.go
Normal file
72
fa/code/src/apps/ch.5.3/main.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Example code for Chapter 5.3 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to run simple CRUD operations using a sqlite driver
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DB_PATH = "./foo.db"
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("sqlite3", DB_PATH)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
|
||||
fmt.Println("Inserting")
|
||||
stmt, err := db.Prepare("INSERT INTO userinfo(username, department, created) values(?,?,?)")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "software developement", time.Now().Format("2006-01-02"))
|
||||
checkErr(err)
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println("id of last inserted row =", id)
|
||||
fmt.Println("Updating")
|
||||
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
|
||||
fmt.Println("Querying")
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username, department, created string
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println("uid | username | department | created")
|
||||
fmt.Printf("%3v | %6v | %8v | %6v\n", uid, username, department, created)
|
||||
}
|
||||
|
||||
fmt.Println("Deleting")
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
23
fa/code/src/apps/ch.5.3/readme.md
Normal file
23
fa/code/src/apps/ch.5.3/readme.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## Set up for `ch.5.3`
|
||||
|
||||
- Step 1) Download and install sqlite 3.
|
||||
- Step 2) Run `sqlite3 foo.db` to create a databased called `foo`.
|
||||
- Step 3) Create the `userinfo` table in sqlite using `schema.sql`.
|
||||
|
||||
Read and run sql statements
|
||||
|
||||
sqlite> .read schema.sql
|
||||
|
||||
Show tables
|
||||
|
||||
sqlite> .tables
|
||||
userinfo
|
||||
|
||||
|
||||
- Step 4) Exit sqlite.
|
||||
|
||||
sqlite> .exit
|
||||
|
||||
- Step 5) Run `go get` to download and install remote packages.
|
||||
- Step 6) Run the program with `go run main.go`
|
||||
|
||||
6
fa/code/src/apps/ch.5.3/schema.sql
Normal file
6
fa/code/src/apps/ch.5.3/schema.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` VARCHAR(64) NULL,
|
||||
`department` VARCHAR(64) NULL,
|
||||
`created` DATE NULL
|
||||
);
|
||||
78
fa/code/src/apps/ch.5.4/main.go
Normal file
78
fa/code/src/apps/ch.5.4/main.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Example code for Chapter 5.4 from "Build Web Application with Golang"
|
||||
// Purpose: Show how to perform CRUD operations using a postgres driver
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
const (
|
||||
DB_USER = "user"
|
||||
DB_PASSWORD = ""
|
||||
DB_NAME = "test"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
|
||||
DB_USER, DB_PASSWORD, DB_NAME)
|
||||
db, err := sql.Open("postgres", dbinfo)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
|
||||
fmt.Println("# Inserting values")
|
||||
|
||||
var lastInsertId int
|
||||
err = db.QueryRow("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;",
|
||||
"astaxie", "software developement", "2012-12-09").Scan(&lastInsertId)
|
||||
checkErr(err)
|
||||
fmt.Println("id of last inserted row =", lastInsertId)
|
||||
|
||||
fmt.Println("# Updating")
|
||||
stmt, err := db.Prepare("update userinfo set username=$1 where uid=$2")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxieupdate", lastInsertId)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
|
||||
fmt.Println("# Querying")
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created time.Time
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println("uid | username | department | created ")
|
||||
fmt.Printf("%3v | %8v | %6v | %6v\n", uid, username, department, created)
|
||||
}
|
||||
|
||||
fmt.Println("# Deleting")
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=$1")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(lastInsertId)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "row(s) changed")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
12
fa/code/src/apps/ch.5.4/readme.md
Normal file
12
fa/code/src/apps/ch.5.4/readme.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## Setup for ch.5.4
|
||||
|
||||
- Step 1) Install and run Postgres
|
||||
- Step 2) Create a user and database according to the constants in `main.go`
|
||||
|
||||
DB_USER = "user"
|
||||
DB_PASSWORD = ""
|
||||
DB_NAME = "test"
|
||||
|
||||
- Step 3) Create table `userinfo` located at `schema.sql`
|
||||
- Step 4) Run `go get` to download and install the remote packages.
|
||||
- Step 5) Execute the program with `go run main.go`
|
||||
9
fa/code/src/apps/ch.5.4/schema.sql
Normal file
9
fa/code/src/apps/ch.5.4/schema.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE userinfo
|
||||
(
|
||||
uid serial NOT NULL,
|
||||
username character varying(100) NOT NULL,
|
||||
departname character varying(500) NOT NULL,
|
||||
Created date,
|
||||
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
|
||||
)
|
||||
WITH (OIDS=FALSE);
|
||||
170
fa/code/src/apps/ch.5.5/main.go
Normal file
170
fa/code/src/apps/ch.5.5/main.go
Normal file
@@ -0,0 +1,170 @@
|
||||
// Example code for Chapter 5.5
|
||||
// Purpose is to show to use BeeDB ORM for basic CRUD operations for sqlite3
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/astaxie/beedb"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"time"
|
||||
)
|
||||
|
||||
var orm beedb.Model
|
||||
|
||||
type Userinfo struct {
|
||||
Uid int `beedb:"PK"`
|
||||
Username string
|
||||
Department string
|
||||
Created string
|
||||
}
|
||||
|
||||
const DB_PATH = "./foo.db"
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
func getTimeStamp() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
func insertUsingStruct() int64 {
|
||||
fmt.Println("insertUsingStruct()")
|
||||
var obj Userinfo
|
||||
obj.Username = "Test Add User"
|
||||
obj.Department = "Test Add Department"
|
||||
obj.Created = getTimeStamp()
|
||||
checkError(orm.Save(&obj))
|
||||
fmt.Printf("%+v\n", obj)
|
||||
return int64(obj.Uid)
|
||||
}
|
||||
func insertUsingMap() int64 {
|
||||
fmt.Println("insertUsingMap()")
|
||||
add := make(map[string]interface{})
|
||||
add["username"] = "astaxie"
|
||||
add["department"] = "cloud develop"
|
||||
add["created"] = getTimeStamp()
|
||||
id, err := orm.SetTable("userinfo").Insert(add)
|
||||
checkError(err)
|
||||
fmt.Println("Last row inserted id =", id)
|
||||
return id
|
||||
}
|
||||
|
||||
func getOneUserInfo(id int64) Userinfo {
|
||||
fmt.Println("getOneUserInfo()")
|
||||
var obj Userinfo
|
||||
checkError(orm.Where("uid=?", id).Find(&obj))
|
||||
return obj
|
||||
}
|
||||
|
||||
func getAllUserInfo(id int64) []Userinfo {
|
||||
fmt.Println("getAllUserInfo()")
|
||||
var alluser []Userinfo
|
||||
checkError(orm.Limit(10).Where("uid>?", id).FindAll(&alluser))
|
||||
return alluser
|
||||
}
|
||||
|
||||
func updateUserinfo(id int64) {
|
||||
fmt.Println("updateUserinfo()")
|
||||
var obj Userinfo
|
||||
obj.Uid = int(id)
|
||||
obj.Username = "Update Username"
|
||||
obj.Department = "Update Department"
|
||||
obj.Created = getTimeStamp()
|
||||
checkError(orm.Save(&obj))
|
||||
fmt.Printf("%+v\n", obj)
|
||||
}
|
||||
|
||||
func updateUsingMap(id int64) {
|
||||
fmt.Println("updateUsingMap()")
|
||||
t := make(map[string]interface{})
|
||||
t["username"] = "updateastaxie"
|
||||
//update one
|
||||
// id, err := orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
|
||||
//update batch
|
||||
lastId, err := orm.SetTable("userinfo").Where("uid>?", id).Update(t)
|
||||
checkError(err)
|
||||
fmt.Println("Last row updated id =", lastId)
|
||||
}
|
||||
|
||||
func getMapsFromSelect(id int64) []map[string][]byte {
|
||||
fmt.Println("getMapsFromSelect()")
|
||||
//Original SQL Backinfo resultsSlice []map[string][]byte
|
||||
//default PrimaryKey id
|
||||
c, err := orm.SetTable("userinfo").SetPK("uid").Where(id).Select("uid,username").FindMap()
|
||||
checkError(err)
|
||||
fmt.Printf("%+v\n", c)
|
||||
return c
|
||||
}
|
||||
|
||||
func groupby() {
|
||||
fmt.Println("groupby()")
|
||||
//Original SQL Group By
|
||||
b, err := orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap()
|
||||
checkError(err)
|
||||
fmt.Printf("%+v\n", b)
|
||||
}
|
||||
|
||||
func joinTables(id int64) {
|
||||
fmt.Println("joinTables()")
|
||||
//Original SQL Join Table
|
||||
a, err := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid").Where("userinfo.uid=?", id).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()
|
||||
checkError(err)
|
||||
fmt.Printf("%+v\n", a)
|
||||
}
|
||||
|
||||
func deleteWithUserinfo(id int64) {
|
||||
fmt.Println("deleteWithUserinfo()")
|
||||
obj := getOneUserInfo(id)
|
||||
id, err := orm.Delete(&obj)
|
||||
checkError(err)
|
||||
fmt.Println("Last row deleted id =", id)
|
||||
}
|
||||
|
||||
func deleteRows() {
|
||||
fmt.Println("deleteRows()")
|
||||
//original SQL delete
|
||||
id, err := orm.SetTable("userinfo").Where("uid>?", 2).DeleteRow()
|
||||
checkError(err)
|
||||
fmt.Println("Last row updated id =", id)
|
||||
}
|
||||
|
||||
func deleteAllUserinfo(id int64) {
|
||||
fmt.Println("deleteAllUserinfo()")
|
||||
//delete all data
|
||||
alluser := getAllUserInfo(id)
|
||||
id, err := orm.DeleteAll(&alluser)
|
||||
checkError(err)
|
||||
fmt.Println("Last row updated id =", id)
|
||||
}
|
||||
func main() {
|
||||
db, err := sql.Open("sqlite3", DB_PATH)
|
||||
checkError(err)
|
||||
orm = beedb.New(db)
|
||||
var lastIdInserted int64
|
||||
|
||||
fmt.Println("Inserting")
|
||||
lastIdInserted = insertUsingStruct()
|
||||
insertUsingMap()
|
||||
|
||||
a := getOneUserInfo(lastIdInserted)
|
||||
fmt.Println(a)
|
||||
|
||||
b := getAllUserInfo(lastIdInserted)
|
||||
fmt.Println(b)
|
||||
|
||||
fmt.Println("Updating")
|
||||
updateUserinfo(lastIdInserted)
|
||||
updateUsingMap(lastIdInserted)
|
||||
|
||||
fmt.Println("Querying")
|
||||
getMapsFromSelect(lastIdInserted)
|
||||
groupby()
|
||||
joinTables(lastIdInserted)
|
||||
|
||||
fmt.Println("Deleting")
|
||||
deleteWithUserinfo(lastIdInserted)
|
||||
deleteRows()
|
||||
deleteAllUserinfo(lastIdInserted)
|
||||
}
|
||||
23
fa/code/src/apps/ch.5.5/readme.md
Normal file
23
fa/code/src/apps/ch.5.5/readme.md
Normal file
@@ -0,0 +1,23 @@
|
||||
## Set up for `ch.5.5`
|
||||
|
||||
- Step 1) Download and install sqlite 3.
|
||||
- Step 2) Run `sqlite3 foo.db` to create a databased called `foo`.
|
||||
- Step 3) Create the tables found in `schema.sql` in sqlite.
|
||||
|
||||
Read and run sql statements
|
||||
|
||||
sqlite> .read schema.sql
|
||||
|
||||
Show tables
|
||||
|
||||
sqlite> .tables
|
||||
userinfo
|
||||
userdetail
|
||||
|
||||
- Step 4) Exit sqlite.
|
||||
|
||||
sqlite> .exit
|
||||
|
||||
- Step 5) Run `go get` to download and install remote packages.
|
||||
- Step 6) Run the program with `go run main.go`
|
||||
|
||||
12
fa/code/src/apps/ch.5.5/schema.sql
Normal file
12
fa/code/src/apps/ch.5.5/schema.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` VARCHAR(64) NULL,
|
||||
`department` VARCHAR(64) NULL,
|
||||
`created` DATE NULL
|
||||
);
|
||||
CREATE TABLE `userdetail` (
|
||||
`uid` INT(10) NULL,
|
||||
`intro` TEXT NULL,
|
||||
`profile` TEXT NULL,
|
||||
PRIMARY KEY (`uid`)
|
||||
);
|
||||
58
fa/code/src/apps/ch.5.6/mongodb/main.go
Normal file
58
fa/code/src/apps/ch.5.6/mongodb/main.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Example code for Chapter 5.6 from "Build Web Application with Golang"
|
||||
// Purpose: Shows you have to perform basic CRUD operations for a mongodb driver.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Phone string
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
DB_NAME = "test"
|
||||
DB_COLLECTION = "people"
|
||||
)
|
||||
|
||||
func main() {
|
||||
session, err := mgo.Dial("localhost")
|
||||
checkError(err)
|
||||
defer session.Close()
|
||||
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
c := session.DB(DB_NAME).C(DB_COLLECTION)
|
||||
err = c.DropCollection()
|
||||
checkError(err)
|
||||
|
||||
ale := Person{"Ale", "555-5555"}
|
||||
cla := Person{"Cla", "555-1234"}
|
||||
|
||||
fmt.Println("Inserting")
|
||||
err = c.Insert(&ale, &cla)
|
||||
checkError(err)
|
||||
|
||||
fmt.Println("Updating")
|
||||
ale.Phone = "555-0101"
|
||||
err = c.Update(bson.M{"name": "Ale"}, &ale)
|
||||
|
||||
fmt.Println("Querying")
|
||||
result := Person{}
|
||||
err = c.Find(bson.M{"name": "Ale"}).One(&result)
|
||||
checkError(err)
|
||||
fmt.Println("Phone:", result.Phone)
|
||||
|
||||
fmt.Println("Deleting")
|
||||
err = c.Remove(bson.M{"name": "Ale"})
|
||||
checkError(err)
|
||||
}
|
||||
6
fa/code/src/apps/ch.5.6/mongodb/readme.md
Normal file
6
fa/code/src/apps/ch.5.6/mongodb/readme.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## Setup for `ch.5.6` for MongoDB
|
||||
|
||||
- Step 1) Install and run MongoDB
|
||||
- Step 2) Launch the MongoDB daemon (mongod) to start the server.
|
||||
- Step 3) Run `go get` to download and install the remote packages.
|
||||
- Step 4) Execute the program with `go run main.go`
|
||||
60
fa/code/src/apps/ch.5.6/redis/main.go
Normal file
60
fa/code/src/apps/ch.5.6/redis/main.go
Normal file
@@ -0,0 +1,60 @@
|
||||
// Example code for Chapter 5.6 from "Build Web Application with Golang"
|
||||
// Purpose: Shows you have to perform basic CRUD operations for a redis driver.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/astaxie/goredis"
|
||||
)
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
DB_PORT = "9191"
|
||||
DB_URL = "127.0.0.1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var client goredis.Client
|
||||
|
||||
// Set the default port in Redis
|
||||
client.Addr = DB_URL + ":" + DB_PORT
|
||||
|
||||
// string manipulation
|
||||
fmt.Println("Inserting")
|
||||
err := client.Set("a", []byte("hello"))
|
||||
checkError(err)
|
||||
|
||||
// list operation
|
||||
vals := []string{"a", "b", "c", "d"}
|
||||
for _, v := range vals {
|
||||
err = client.Rpush("l", []byte(v))
|
||||
checkError(err)
|
||||
}
|
||||
fmt.Println("Updating")
|
||||
err = client.Set("a", []byte("a is for apple"))
|
||||
checkError(err)
|
||||
err = client.Rpush("l", []byte("e"))
|
||||
checkError(err)
|
||||
|
||||
fmt.Println("Querying")
|
||||
val, err := client.Get("a")
|
||||
checkError(err)
|
||||
fmt.Println(string(val))
|
||||
|
||||
dbvals, err := client.Lrange("l", 0, 4)
|
||||
checkError(err)
|
||||
for i, v := range dbvals {
|
||||
println(i, ":", string(v))
|
||||
}
|
||||
|
||||
fmt.Println("Deleting")
|
||||
_, err = client.Del("l")
|
||||
checkError(err)
|
||||
_, err = client.Del("a")
|
||||
checkError(err)
|
||||
}
|
||||
10
fa/code/src/apps/ch.5.6/redis/readme.md
Normal file
10
fa/code/src/apps/ch.5.6/redis/readme.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## Setup for `ch.5.6` for Redis
|
||||
|
||||
- Step 1) Install and run Redis
|
||||
- Step 2) Launch the Redis server matching the DB constants.
|
||||
|
||||
DB_PORT = "9191"
|
||||
DB_URL = "127.0.0.1"
|
||||
|
||||
- Step 3) Run `go get` to download and install the remote packages.
|
||||
- Step 4) Execute the program with `go run main.go`
|
||||
12
fa/code/src/mymath/sqrt.go
Normal file
12
fa/code/src/mymath/sqrt.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Example code for Chapter 1.2 from "Build Web Application with Golang"
|
||||
// Purpose: Shows how to create a simple package called `mymath`
|
||||
// This package must be imported from another go file to run.
|
||||
package mymath
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
z := 0.0
|
||||
for i := 0; i < 1000; i++ {
|
||||
z -= (z*z - x) / (2 * x)
|
||||
}
|
||||
return z
|
||||
}
|
||||
Reference in New Issue
Block a user