├── LICENSE ├── README.md ├── custom-error-handling.go ├── doubly-linked-list.go ├── eclipse-class-filter.png ├── golang-gopher.png ├── httpserver.go ├── images └── cedar-tree.png ├── jsoncfgo-a-json-config-file-reader.go ├── map-of-car-options.go ├── polymorphic_shapes.go ├── pta.png └── www ├── ajax.html ├── form.html ├── help.html ├── test1.html └── test2.html /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Lex Sheehan, LLC 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Code Examples 2 | 3 | 4 | 5 | The best way to learn is by example. 6 | 7 | This is a collection of Go code examples that demonstrate various concepts. 8 | 9 | Read the companion articles at the [Golang Code Examples web site] (http://l3x.github.io/golang-code-examples/). 10 | 11 | These examples could be useful for your projects, thesis and learning. 12 | 13 | Feel free to use any of the code examples in your endeavors. 14 | 15 | I hope this ressource is helpful to you. 16 | 17 | Best Regards, 18 | 19 | Lex 20 | 21 | ## Audience 22 | 23 | This reference has been prepared for programmers with beginning to intermediate level experience with Go to help understand concepts related to the Go programming language. 24 | 25 | ## Prerequisites 26 | 27 | I'm making the assumption that you are already familiar with Golang and it's concepts. 28 | 29 | If not, see the references section below. 30 | 31 | ### Supported Platforms 32 | * darwin/386 33 | * darwin/amd64 34 | * freebsd/386 35 | * freebsd/amd64 36 | * linux/386 37 | * linux/amd64 38 | * linux/arm 39 | * windows/386 40 | * windows/amd64 41 | 42 | ## Running Examples 43 | 44 | Each code example can be run from the command line like this: ```$ go run ``` 45 | 46 | ## References 47 | 48 | * [Golang Code Examples web site] (http://l3x.github.io/golang-code-examples/) 49 | * [A Tour of Go] (http://tour.golang.org/) 50 | * [An Introduction to Programming in Go] (http://www.golang-book.com/) 51 | * [How to Write Go Code] (http://golang.org/doc/code.html) 52 | * [Application Development with Lex Sheehan] (http://lexsheehan.blogspot.com/) 53 | 54 | ### License 55 | This project is licensed under a Simplified BSD license. Please read the [LICENSE file](LICENSE). -------------------------------------------------------------------------------- /custom-error-handling.go: -------------------------------------------------------------------------------- 1 | /* 2 | filename: custom-error-handling.go 3 | author: Lex Sheehan 4 | copyright: Lex Sheehan LLC 5 | license: GPL 6 | status: published 7 | comments: http://l3x.github.io/golang-code-examples/2014/07/14/custom-error-handling.html 8 | */ 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "time" 14 | ) 15 | 16 | type Err struct { 17 | errNo int 18 | when time.Time 19 | msg string 20 | } 21 | 22 | func (e *Err) Error() string { 23 | return fmt.Sprintf("%v [%d] %s", e.when, e.errNo, e.msg) 24 | } 25 | func (err Err) errorNumber() int { 26 | return err.errNo 27 | } 28 | 29 | type ErrWidget_A struct { 30 | Err // Err is an embedded struct - ErrWidget_A inherits it's data and behavior 31 | } 32 | // a behavior only available for the ErrWidget_A 33 | func (e ErrWidget_A) Error() string { 34 | fmt.Println("do special ErrWidget_A thing...") 35 | return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg) 36 | } 37 | // a behavior only available for the ErrWidget_A 38 | func (e ErrWidget_A) optionalErrHandlingOperation() { 39 | fmt.Println("Email the admins...\n") 40 | } 41 | 42 | type ErrWidget_B struct { 43 | Err // Err is an embedded struct - ErrWidget_B inherits it's data and behavior 44 | } 45 | // a behavior only available for the Widget_B 46 | func (e ErrWidget_B) Error() string { 47 | fmt.Println("do special Widget_B thing...") 48 | return fmt.Sprintf("%s [%d] %s", e.when, e.errNo, e.msg) 49 | } 50 | // a behavior only available for the Widget_B 51 | func (e ErrWidget_B) optionalErrHandlingOperation() { 52 | fmt.Println("SMS operations manager...\n") 53 | } 54 | 55 | func run() error { 56 | return &Err{ 57 | 8001, 58 | time.Now(), 59 | "generic error occurred\n", 60 | } 61 | } 62 | 63 | func run2() *ErrWidget_B { 64 | errB := new(ErrWidget_B) 65 | errB.errNo = 6001 66 | errB.when = time.Now() 67 | errB.msg = "Widget_B error occurred" 68 | return errB 69 | } 70 | 71 | func RunWidget(modelNo int) (string, error) { 72 | // Run valid widgets 73 | switch modelNo { 74 | case 1: 75 | return fmt.Sprintf("run widget model %d", modelNo), nil 76 | case 2: 77 | return fmt.Sprintf("run widget model %d", modelNo), nil 78 | default: 79 | // Error condition - unknown widget model number 80 | errA := new(ErrWidget_A) 81 | errA.errNo = 5002 82 | errA.when = time.Now() 83 | errA.msg = "Widget_A error occurred" 84 | return fmt.Sprintf("unable to run unknown model %d", modelNo), errA 85 | } 86 | } 87 | 88 | // Split multiple (variadic) return values into a slice of values 89 | // in this case, where [0] = value and [1] = the error message 90 | func split(args ...interface{}) []interface{} { 91 | return args 92 | } 93 | 94 | func main() { 95 | 96 | // Execute RunWidget function and handle error if necessary 97 | msg := "" 98 | // RunWidget(1) succeeds 99 | x := split(RunWidget(1)) 100 | msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])} 101 | fmt.Printf("RunWidget(1) => result(%s)" + msg, x[0]) 102 | 103 | // RunWidget(2) succeeds 104 | x = split(RunWidget(2)) 105 | msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])} 106 | fmt.Printf("RunWidget(2) => result(%s)" + msg, x[0]) 107 | 108 | // RunWidget(666) fails - 109 | x = split(RunWidget(666)) 110 | msg = "\n\n"; if x[1] != nil {msg = fmt.Sprintf(", err(%v)\n\n", x[1])} 111 | fmt.Printf("RunWidget(666) => result(%s)" + msg, x[0]) 112 | 113 | 114 | // Throw generic custom error type and handle it 115 | if err := run(); err != nil { fmt.Println(err) } 116 | 117 | // Throw ErrWidget_B error and handle it by printing and running optional custom behavior 118 | widget_B_error := run2(); if widget_B_error.errNo != 0 { 119 | fmt.Println(widget_B_error) 120 | } 121 | fmt.Println("") 122 | 123 | 124 | timeNow := time.Now() 125 | // Create and print ErrWidget_A, then call custom behavior 126 | a := ErrWidget_A {Err{5001, timeNow, "test"}} 127 | fmt.Println(a) // fmt will execute Error() method that can have special behavior 128 | fmt.Println("A ErrWidget_A has this error number: ", a.errorNumber()) 129 | a.optionalErrHandlingOperation() // Widget_A emails admins 130 | 131 | // Create ErrWidget_B, then call custom behavior 132 | b := ErrWidget_B {Err{6001, timeNow, "test"}} 133 | fmt.Println("A ErrWidget_B has this error number: ", b.errorNumber()) 134 | b.optionalErrHandlingOperation() // Widget_B sends SMS message to managers 135 | // Since b was not printed by fmt, the special ErrWidget_B behavior is not triggered 136 | } 137 | -------------------------------------------------------------------------------- /doubly-linked-list.go: -------------------------------------------------------------------------------- 1 | /* 2 | filename: doubly-linked-list.go 3 | author: Lex Sheehan 4 | copyright: Lex Sheehan LLC 5 | license: GPL 6 | status: published 7 | comments: http://l3x.github.io/golang-code-examples/2014/07/23/doubly-linked-list.html 8 | */ 9 | package main 10 | import ( 11 | "fmt" 12 | "errors" 13 | "strings" 14 | ) 15 | type Value struct { 16 | Name string 17 | MilesAway int 18 | } 19 | type Node struct { 20 | Value // Embedded struct 21 | next, prev *Node 22 | } 23 | type List struct { 24 | head, tail *Node 25 | } 26 | func (l *List) First() *Node { 27 | return l.head 28 | } 29 | func (n *Node) Next() *Node { 30 | return n.next 31 | } 32 | func (n *Node) Prev() *Node { 33 | return n.prev 34 | } 35 | // Create new node with value 36 | func (l *List) Push(v Value) *List { 37 | n := &Node{Value: v} 38 | if l.head == nil { 39 | l.head = n // First node 40 | } else { 41 | l.tail.next = n // Add after prev last node 42 | n.prev = l.tail // Link back to prev last node 43 | } 44 | l.tail = n // reset tail to newly added node 45 | return l 46 | } 47 | func (l *List) Find(name string) *Node { 48 | found := false 49 | var ret *Node = nil 50 | for n := l.First(); n != nil && !found; n = n.Next() { 51 | if n.Value.Name == name { 52 | found = true 53 | ret = n 54 | } 55 | } 56 | return ret 57 | } 58 | func (l *List) Delete(name string) bool { 59 | success := false 60 | node2del := l.Find(name) 61 | if node2del != nil { 62 | fmt.Println("Delete - FOUND: ", name) 63 | prev_node := node2del.prev 64 | next_node := node2del.next 65 | // Remove this node 66 | prev_node.next = node2del.next 67 | next_node.prev = node2del.prev 68 | success = true 69 | } 70 | return success 71 | } 72 | var errEmpty = errors.New("ERROR - List is empty") 73 | // Pop last item from list 74 | func (l *List) Pop() (v Value, err error) { 75 | if l.tail == nil { 76 | err = errEmpty 77 | } else { 78 | v = l.tail.Value 79 | l.tail = l.tail.prev 80 | if l.tail == nil { 81 | l.head = nil 82 | } 83 | } 84 | return v, err 85 | } 86 | 87 | func main() { 88 | dashes := strings.Repeat("-", 50) 89 | l := new(List) // Create Doubly Linked List 90 | 91 | l.Push(Value{Name: "Atlanta", MilesAway: 0}) 92 | l.Push(Value{Name: "Las Vegas", MilesAway: 1961}) 93 | l.Push(Value{Name: "New York", MilesAway: 881}) 94 | 95 | processed := make(map[*Node]bool) 96 | 97 | fmt.Println("First time through list...") 98 | for n := l.First(); n != nil; n = n.Next() { 99 | fmt.Printf("%v\n", n.Value) 100 | if processed[n] { 101 | fmt.Printf("%s as been processed\n", n.Value) 102 | } 103 | processed[n] = true 104 | } 105 | fmt.Println(dashes) 106 | fmt.Println("Second time through list...") 107 | for n := l.First(); n != nil; n = n.Next() { 108 | fmt.Printf("%v", n.Value) 109 | if processed[n] { 110 | fmt.Println(" has been processed") 111 | } else { fmt.Println() } 112 | processed[n] = true 113 | } 114 | 115 | fmt.Println(dashes) 116 | var found_node *Node 117 | city_to_find := "New York" 118 | found_node = l.Find(city_to_find) 119 | if found_node == nil { 120 | fmt.Printf("NOT FOUND: %v\n", city_to_find) 121 | } else { 122 | fmt.Printf("FOUND: %v\n", city_to_find) 123 | } 124 | 125 | city_to_find = "Chicago" 126 | found_node = l.Find(city_to_find) 127 | if found_node == nil { 128 | fmt.Printf("NOT FOUND: %v\n", city_to_find) 129 | } else { 130 | fmt.Printf("FOUND: %v\n", city_to_find) 131 | } 132 | 133 | fmt.Println(dashes) 134 | city_to_remove := "Las Vegas" 135 | successfully_removed_city := l.Delete(city_to_remove) 136 | if successfully_removed_city { 137 | fmt.Printf("REMOVED: %v\n", city_to_remove) 138 | } else { 139 | fmt.Printf("DID NOT REMOVE: %v\n", city_to_remove) 140 | } 141 | 142 | city_to_remove = "Chicago" 143 | successfully_removed_city = l.Delete(city_to_remove) 144 | if successfully_removed_city { 145 | fmt.Printf("REMOVED: %v\n", city_to_remove) 146 | } else { 147 | fmt.Printf("DID NOT REMOVE: %v\n", city_to_remove) 148 | } 149 | 150 | fmt.Println(dashes) 151 | fmt.Println("* Pop each value off list...") 152 | for v, err := l.Pop(); err == nil; v, err = l.Pop() { 153 | fmt.Printf("%v\n", v) 154 | } 155 | fmt.Println(l.Pop()) // Generate error - attempt to pop from empty list 156 | } 157 | -------------------------------------------------------------------------------- /eclipse-class-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3x/golang-code-examples/a752ccf90134637c4226ff7d22e3c73b1e608cc2/eclipse-class-filter.png -------------------------------------------------------------------------------- /golang-gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3x/golang-code-examples/a752ccf90134637c4226ff7d22e3c73b1e608cc2/golang-gopher.png -------------------------------------------------------------------------------- /httpserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "errors" 7 | "net/http" 8 | "io/ioutil" 9 | "html/template" 10 | "regexp" 11 | "encoding/json" 12 | "github.com/l3x/jsoncfgo" 13 | "github.com/go-goodies/go_utils" 14 | ) 15 | 16 | var Dir string 17 | var Users jsoncfgo.Obj 18 | var AppContext *go_utils.Singleton 19 | 20 | func HtmlFileHandler(response http.ResponseWriter, request *http.Request, filename string){ 21 | response.Header().Set("Content-type", "text/html") 22 | webpage, err := ioutil.ReadFile(Dir + filename) // read whole the file 23 | if err != nil { 24 | http.Error(response, fmt.Sprintf("%s file error %v", filename, err), 500) 25 | } 26 | fmt.Fprint(response, string(webpage)); 27 | } 28 | 29 | func HelpHandler(response http.ResponseWriter, request *http.Request){ 30 | HtmlFileHandler(response, request, "/help.html") 31 | } 32 | 33 | func AjaxHandler(response http.ResponseWriter, request *http.Request){ 34 | HtmlFileHandler(response, request, "/ajax.html") 35 | } 36 | 37 | func printCookies(response http.ResponseWriter, request *http.Request) { 38 | cookieNameForUsername := AppContext.Data["CookieNameForUsername"].(string) 39 | fmt.Println("COOKIES:") 40 | for _, cookie := range request.Cookies() { 41 | fmt.Printf("%v: %v\n", cookie.Name, cookie.Value) 42 | if cookie.Name == cookieNameForUsername { 43 | SetUsernameCookie(response, cookie.Value) 44 | } 45 | }; fmt.Println("") 46 | } 47 | 48 | func UserHandler(response http.ResponseWriter, request *http.Request){ 49 | response.Header().Set("Content-type", "application/json") 50 | // json data to send to client 51 | data := map[string]string { "api" : "user", "name" : "" } 52 | userApiURL := regexp.MustCompile(`^/user/(\w+)$`) 53 | usernameMatches := userApiURL.FindStringSubmatch(request.URL.Path) 54 | // regex matches example: ["/user/joesample", "joesample"] 55 | if len(usernameMatches) > 0 { 56 | printCookies(response, request) 57 | var userName string 58 | userName = usernameMatches[1] // ex: joesample 59 | userObj := AppContext.Data[userName] 60 | fmt.Printf("userObj: %v\n", userObj) 61 | if userObj == nil { 62 | msg := fmt.Sprintf("Invalid username (%s)", userName) 63 | panic(errors.New(msg)) 64 | } else { 65 | // Send JSON to the client 66 | thisUser := userObj.(jsoncfgo.Obj) 67 | fmt.Printf("thisUser: %v\n", thisUser) 68 | data["name"] = thisUser["firstname"].(string) + " " + thisUser["lastname"].(string) 69 | } 70 | json_bytes, _ := json.Marshal(data) 71 | fmt.Printf("json_bytes: %s\n", string(json_bytes[:])) 72 | fmt.Fprintf(response, "%s\n", json_bytes) 73 | 74 | } else { 75 | http.Error(response, "404 page not found", 404) 76 | } 77 | } 78 | 79 | func SetUsernameCookie(response http.ResponseWriter, userName string){ 80 | // Add cookie to response 81 | cookieName := AppContext.Data["CookieNameForUsername"].(string) 82 | cookie := http.Cookie{Name: cookieName, Value: userName} 83 | http.SetCookie(response, &cookie) 84 | } 85 | 86 | func DebugFormHandler(response http.ResponseWriter, request *http.Request){ 87 | 88 | printCookies(response, request) 89 | 90 | err := request.ParseForm() // Parse URL and POST data into request.Form 91 | if err != nil { 92 | http.Error(response, fmt.Sprintf("error parsing url %v", err), 500) 93 | } 94 | 95 | // Set cookie and MIME type in the HTTP headers. 96 | fmt.Printf("request.Form: %v\n", request.Form) 97 | if request.Form["username"] != nil { 98 | cookieVal := request.Form["username"][0] 99 | fmt.Printf("cookieVal: %s\n", cookieVal) 100 | SetUsernameCookie(response, cookieVal) 101 | }; fmt.Println("") 102 | 103 | templateHandler(response, request) 104 | response.Header().Set("Content-type", "text/plain") 105 | 106 | // Send debug diagnostics to client 107 | fmt.Fprintf(response, "") 108 | fmt.Fprintf(response, "", request.Method) 109 | fmt.Fprintf(response, "", request.RequestURI) 110 | fmt.Fprintf(response, "", request.URL.Path) 111 | fmt.Fprintf(response, "", request.Form) 112 | fmt.Fprintf(response, "", request.Cookies()) 113 | fmt.Fprintf(response, "
request.Method '%v'
request.RequestURI'%v'
request.URL.Path '%v'
request.Form '%v'
request.Cookies() '%v'
") 114 | 115 | } 116 | 117 | func DebugQueryHandler(response http.ResponseWriter, request *http.Request){ 118 | 119 | // Set cookie and MIME type in the HTTP headers. 120 | response.Header().Set("Content-type", "text/plain") 121 | 122 | // Parse URL and POST data into the request.Form 123 | err := request.ParseForm() 124 | if err != nil { 125 | http.Error(response, fmt.Sprintf("error parsing url %v", err), 500) 126 | } 127 | 128 | // Send debug diagnostics to client 129 | fmt.Fprintf(response, " request.Method '%v'\n", request.Method) 130 | fmt.Fprintf(response, " request.RequestURI '%v'\n", request.RequestURI) 131 | fmt.Fprintf(response, " request.URL.Path '%v'\n", request.URL.Path) 132 | fmt.Fprintf(response, " request.Form '%v'\n", request.Form) 133 | fmt.Fprintf(response, " request.Cookies() '%v'\n", request.Cookies()) 134 | } 135 | 136 | func templateHandler(w http.ResponseWriter, r *http.Request) { 137 | t, _ := template.New("form.html").Parse(form) 138 | t.Execute(w, "") 139 | } 140 | 141 | func formHandler(w http.ResponseWriter, r *http.Request) { 142 | log.Println(r.Form) 143 | templateHandler(w, r) 144 | } 145 | 146 | var form = ` 147 |

Debug Info (POST form)

148 |
149 |
150 | 151 | 153 |
154 |
155 |
156 | 157 | 158 | ` 159 | 160 | func errorHandler(f func(http.ResponseWriter, *http.Request) error) http.HandlerFunc { 161 | return func(w http.ResponseWriter, r *http.Request) { 162 | log.Println("errorHandler...") 163 | err := f(w, r) 164 | if err != nil { 165 | http.Error(w, err.Error(), http.StatusInternalServerError) 166 | log.Printf("handling %q: %v", r.RequestURI, err) 167 | } 168 | } 169 | } 170 | 171 | func doThis() error { return nil } 172 | func doThat() error { return errors.New("ERROR - doThat") } 173 | 174 | func wrappedHandler(w http.ResponseWriter, r *http.Request) error { 175 | log.Println("betterHandler...") 176 | if err := doThis(); err != nil { 177 | return fmt.Errorf("doing this: %v", err) 178 | } 179 | 180 | if err := doThat(); err != nil { 181 | return fmt.Errorf("doing that: %v", err) 182 | } 183 | return nil 184 | } 185 | 186 | 187 | func main() { 188 | cfg := jsoncfgo.Load("/Users/lex/dev/go/data/webserver/webserver-config.json") 189 | 190 | host := cfg.OptionalString("host", "localhost") 191 | fmt.Printf("host: %v\n", host) 192 | 193 | port := cfg.OptionalInt("port", 8080) 194 | fmt.Printf("port: %v\n", port) 195 | 196 | Dir = cfg.OptionalString("dir", "www/") 197 | fmt.Printf("web_dir: %v\n", Dir) 198 | 199 | redirect_code := cfg.OptionalInt("redirect_code", 307) 200 | fmt.Printf("redirect_code: %v\n\n", redirect_code) 201 | 202 | mux := http.NewServeMux() 203 | 204 | fileServer := http.Dir(Dir) 205 | fileHandler := http.FileServer(fileServer) 206 | mux.Handle("/", fileHandler) 207 | 208 | rdh := http.RedirectHandler("http://example.org", redirect_code) 209 | mux.Handle("/redirect", rdh) 210 | mux.Handle("/notFound", http.NotFoundHandler()) 211 | 212 | mux.Handle("/help", http.HandlerFunc( HelpHandler )) 213 | 214 | mux.Handle("/debugForm", http.HandlerFunc( DebugFormHandler )) 215 | mux.Handle("/debugQuery", http.HandlerFunc( DebugQueryHandler )) 216 | 217 | mux.Handle("/user/", http.HandlerFunc( UserHandler )) 218 | mux.Handle("/ajax", http.HandlerFunc( AjaxHandler )) 219 | 220 | mux.Handle("/adapter", errorHandler(wrappedHandler)) 221 | 222 | log.Printf("Running on port %d\n", port) 223 | 224 | addr := fmt.Sprintf("%s:%d", host, port) 225 | 226 | Users := jsoncfgo.Load("/Users/lex/dev/go/data/webserver/users.json") 227 | 228 | joesample := Users.OptionalObject("joesample") 229 | fmt.Printf("joesample: %v\n", joesample) 230 | fmt.Printf("joesample['firstname']: %v\n", joesample["firstname"]) 231 | fmt.Printf("joesample['lastname']: %v\n\n", joesample["lastname"]) 232 | 233 | alicesmith := Users.OptionalObject("alicesmith") 234 | fmt.Printf("alicesmith: %v\n", alicesmith) 235 | fmt.Printf("alicesmith['firstname']: %v\n", alicesmith["firstname"]) 236 | fmt.Printf("alicesmith['lastname']: %v\n\n", alicesmith["lastname"]) 237 | 238 | bobbrown := Users.OptionalObject("bobbrown") 239 | fmt.Printf("bobbrown: %v\n", bobbrown) 240 | fmt.Printf("bobbrown['firstname']: %v\n", bobbrown["firstname"]) 241 | fmt.Printf("bobbrown['lastname']: %v\n\n", bobbrown["lastname"]) 242 | 243 | AppContext = go_oops.NewSingleton() 244 | AppContext.Data["CookieNameForUsername"] = "testapp-username" 245 | AppContext.Data["joesample"] = joesample 246 | AppContext.Data["alicesmith"] = alicesmith 247 | AppContext.Data["bobbrown"] = bobbrown 248 | fmt.Printf("AppContext: %v\n", AppContext) 249 | fmt.Printf("AppContext.Data[\"joesample\"]: %v\n", AppContext.Data["joesample"]) 250 | fmt.Printf("AppContext.Data[\"alicesmith\"]: %v\n", AppContext.Data["alicesmith"]) 251 | fmt.Printf("AppContext.Data[\"bobbrown\"]: %v\n\n", AppContext.Data["bobbrown"]) 252 | 253 | err := http.ListenAndServe(addr, mux) 254 | fmt.Println(err.Error()) 255 | } 256 | -------------------------------------------------------------------------------- /images/cedar-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3x/golang-code-examples/a752ccf90134637c4226ff7d22e3c73b1e608cc2/images/cedar-tree.png -------------------------------------------------------------------------------- /jsoncfgo-a-json-config-file-reader.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | "log" 7 | "github.com/l3x/jsoncfgo" 8 | ) 9 | 10 | func main() { 11 | 12 | cfg := jsoncfgo.Load("/Users/lex/dev/go/data/jsoncfgo/simple-config.json") 13 | 14 | host := cfg.String("host") 15 | fmt.Printf("host: %v\n", host) 16 | bogusHost := cfg.String("bogusHost", "default_host_name") 17 | fmt.Printf("host: %v\n\n", bogusHost) 18 | 19 | port := cfg.Int("port") 20 | fmt.Printf("port: %v\n", port) 21 | bogusPort := cfg.Int("bogusPort", 9000) 22 | fmt.Printf("bogusPort: %v\n\n", bogusPort) 23 | 24 | bigNumber := cfg.Int64("bignNumber") 25 | fmt.Printf("bigNumber: %v\n", bigNumber) 26 | bogusBigNumber := cfg.Int64("bogusBigNumber", 9000000000000000000) 27 | fmt.Printf("bogusBigNumber: %v\n\n", bogusBigNumber) 28 | 29 | active := cfg.Bool("active") 30 | fmt.Printf("active: %v\n", active) 31 | bogusFalseActive := cfg.Bool("bogusFalseActive", false) 32 | fmt.Printf("bogusFalseActive: %v\n", bogusFalseActive) 33 | bogusTrueActive := cfg.Bool("bogusTrueActive", true) 34 | fmt.Printf("bogusTrueActive: %v\n\n", bogusTrueActive) 35 | 36 | appList := cfg.List("appList") 37 | fmt.Printf("appList: %v\n", appList) 38 | bogusAppList := cfg.List("bogusAppList", []string{"app1", "app2", "app3"}) 39 | fmt.Printf("bogusAppList: %v\n\n", bogusAppList) 40 | 41 | numbers := cfg.IntList("numbers") 42 | fmt.Printf("numbers: %v\n", numbers) 43 | bogusSettings := cfg.IntList("bogusSettings", []int64{1, 2, 3}) 44 | fmt.Printf("bogusAppList: %v\n\n", bogusSettings) 45 | 46 | if err := cfg.Validate(); err != nil { 47 | time.Sleep(100 * time.Millisecond) 48 | defer log.Fatalf("ERROR - Invalid config file...\n%v", err) 49 | return 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /map-of-car-options.go: -------------------------------------------------------------------------------- 1 | /* 2 | filename: map-of-car-options.go 3 | author: Lex Sheehan 4 | copyright: Lex Sheehan LLC 5 | license: GPL 6 | status: published 7 | comments: http://l3x.github.io/golang-code-examples/2014/07/22/map-of-car-options.html 8 | */ 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "strings" 14 | ) 15 | 16 | type Car struct { 17 | Make string 18 | Model string 19 | Options []string 20 | } 21 | 22 | func main() { 23 | 24 | dashes := strings.Repeat("-", 50) 25 | 26 | is250 := &Car{"Lexus", "IS250", []string{"GPS", "Alloy Wheels", "Roof Rack", "Power Outlets", "Heated Seats"}} 27 | accord := &Car{"Honda", "Accord", []string{"Alloy Wheels", "Roof Rack"}} 28 | blazer := &Car{"Chevy", "Blazer", []string{"GPS", "Roof Rack", "Power Outlets"}} 29 | 30 | cars := []*Car{is250, accord, blazer} 31 | fmt.Printf("Cars:\n%v\n\n", cars) // cars is a slice of pointers to our three cars 32 | 33 | // Create a map to associate options with each car 34 | car_options := make(map[string][]*Car) 35 | 36 | fmt.Printf("CARS:\n%s\n", dashes) 37 | for _, car := range cars { 38 | fmt.Printf("%v\n", car) 39 | for _, option := range car.Options { 40 | // Associate this car with each of it's options 41 | car_options[option] = append(car_options[option], car) 42 | fmt.Printf("car_options[option]: %s\n", option) 43 | } 44 | fmt.Println(dashes) 45 | } 46 | fmt.Println(dashes) 47 | 48 | // Print a list of cars with the "GPS" option 49 | for _, p := range car_options["GPS"] { 50 | fmt.Println(p.Make, "has GPS.") 51 | } 52 | 53 | fmt.Println("") 54 | fmt.Println(len(car_options["Alloy Wheels"]), "has Alloy Wheels.") 55 | } 56 | 57 | -------------------------------------------------------------------------------- /polymorphic_shapes.go: -------------------------------------------------------------------------------- 1 | /* 2 | filename: polymorphic_shapes.go 3 | author: Lex Sheehan 4 | copyright: Lex Sheehan LLC 5 | license: GPL 6 | status: published 7 | comments: http://l3x.github.io/golang-code-examples/2014/07/14/custom-error-handling.html 8 | */ 9 | package main // Executable commands must always use package main. 10 | 11 | import ( 12 | "fmt" // fmt.Println formats output to console 13 | "math" // provides math.Sqrt function 14 | ) 15 | 16 | // ---------------------- 17 | // Shape interface 18 | // ---------------------- 19 | // Shape interface defines a method set (consisting of the area method) 20 | type Shape interface { 21 | area() float64 // any type that implements an area method is considered a Shape 22 | } 23 | // Calculate total area of all shapes via polymorphism (all shapes implement the area method) 24 | func totalArea(shapes ...Shape) float64 { // Use interface type as as function argument 25 | var area float64 // "..." makes shapes "variadic" (can send one or more) 26 | for _, s := range shapes { 27 | area += s.area() // the current Shape implements/receives the area method 28 | } // go passes the pointer to the shape to the area method 29 | return area 30 | } 31 | 32 | // ---------------------- 33 | // Drawer interface 34 | // ---------------------- 35 | type Drawer interface { 36 | draw() // does not return a type 37 | } 38 | func drawShape(d Drawer) { // associate this method with the Drawer interface 39 | d.draw() 40 | } 41 | 42 | // ---------------------- 43 | // Circle Type 44 | // ---------------------- 45 | type Circle struct { // Since "Circle" is capitalized, it is visible outside this package 46 | x, y, r float64 // a Circle struct is a collection of fields: x, y, r 47 | } 48 | // Circle implements Shape interface b/c it has an area method 49 | // area is a method, which is special type of function that is associated with the Circle struct 50 | // The Circle struct becomes the "receiver" of this method, so we can use the "." operator 51 | func (c *Circle) area() float64 { // dereference Circle type (data pointed to by c) 52 | return math.Pi * c.r * c.r // Pi is a constant in the math package 53 | } 54 | func (c Circle) draw() { 55 | fmt.Println("Circle drawing with radius: ", c.r) // encapsulated draw implementation for Circle type 56 | } 57 | // ---------------------- 58 | // Rectangle Type 59 | // ---------------------- 60 | type Rectangle struct { // a struct contains named fields of data 61 | x1, y1, x2, y2 float64 // define multiple fields with same data type on one line 62 | } 63 | func distance(x1, y1, x2, y2 float64) float64 { // lowercase functin name visible only in this package 64 | a := x2 - x1 65 | b := y2 - y1 66 | return math.Sqrt(a * a + b * b) 67 | } 68 | // Rectangle implements Shape interface b/c it has an area method 69 | func (r *Rectangle) area() float64 { 70 | l := distance(r.x1, r.y1, r.x1, r.y2) // define and assign local variable "l" 71 | w := distance(r.x1, r.y1, r.x2, r.y1) // l and w only available within scope of area function 72 | return l * w 73 | } 74 | func (r Rectangle) draw() { 75 | fmt.Printf("Rectangle drawing with point1: (%f, %f) and point2: (%f, %f)\n", r.x1, r.y1, r.x2, r.y2) 76 | } 77 | // ---------------------- 78 | // MultiShape Type 79 | // ---------------------- 80 | type MultiShape struct { 81 | shapes []Shape // shapes field is a slice of interfaces 82 | } 83 | // 84 | func (m *MultiShape) area() float64 { 85 | var area float64 86 | for _, shape := range m.shapes { // iterate through shapes ("_" indicates that index is not used) 87 | area += shape.area() // execute polymorphic area method for this shape 88 | } 89 | return area 90 | } 91 | 92 | func main() { 93 | c := Circle{0, 0, 5} // initialize new instance of Circle type by field order "struct literal" 94 | // The new function allocates memory for all fields, sets each to their zero value and returns a pointer 95 | c2 := new(Circle) // c2 is a pointer to the instantiated Circle type 96 | c2.x = 0; c2.y = 0; c2.r = 10 // initialize data with multiple statements on one line 97 | fmt.Println("Circle Area:", totalArea(&c)) // pass address of circle (c) 98 | fmt.Println("Circle2 Area:", totalArea(c2)) // c2 was defined using built-in new function 99 | r := Rectangle{x1: 0, y1: 0, x2: 5, y2: 5} // "struct literal" rectangle (r) initialized by field name 100 | fmt.Println("Rectangle Area:", totalArea(&r)) // pass address of rectangle (r) 101 | fmt.Println("Rectangle + Circle Area:", totalArea(&c, c2, &r)) // can pass multiple shapes 102 | m := MultiShape{[]Shape{&r, &c, c2}} // pass slice of shapes 103 | fmt.Println("Multishape Area:", totalArea(&m)) // calculate total area of all shapes 104 | fmt.Println("Area Totals:", totalArea(&c, c2, &r)) // c2 is a pointer to a circle, &c and &r are addresses of shapes 105 | fmt.Println("2 X Area Totals:", totalArea(&c, c2, &r, &m)) // twice the size of all areas 106 | drawShape(c) // execute polymorphic method call 107 | drawShape(c2) 108 | drawShape(r) 109 | } 110 | -------------------------------------------------------------------------------- /pta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3x/golang-code-examples/a752ccf90134637c4226ff7d22e3c73b1e608cc2/pta.png -------------------------------------------------------------------------------- /www/ajax.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | go server example 6 | 7 | 8 | 9 | 10 | 34 | 35 | 36 |

Ajax Example

37 | 38 |
39 | The user's full name is: ? 40 |
41 |
42 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /www/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | go web server example 6 | 7 | 8 | 9 |
10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /www/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | go web server example 6 | 9 | 10 | 11 |

go web server example

12 | 13 |

Help (this page)

14 |

File Server (dir value from config file)

15 |

Redirect (to example.com)

16 |

NotFound Handler (should get a 404 error)

17 |

Debug Info (POST form)

18 |

Debug Info (GET request)

19 |

Ajax Callback

20 |

Function Adapter

21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /www/test1.html: -------------------------------------------------------------------------------- 1 | one 2 | -------------------------------------------------------------------------------- /www/test2.html: -------------------------------------------------------------------------------- 1 | two 2 | --------------------------------------------------------------------------------