Skip to content

Instantly share code, notes, and snippets.

@yingmu52
Last active November 12, 2017 21:40
Show Gist options
  • Save yingmu52/5461518857db1828417a43dde228f836 to your computer and use it in GitHub Desktop.
Save yingmu52/5461518857db1828417a43dde228f836 to your computer and use it in GitHub Desktop.
Setup Go Environment

Install & Setup

Note: all the go code should be inside this go folder

  • Set your GOPATH
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
echo "export GOPATH=$HOME/go" >> .bash_profile
  • Check if install & setup successfully
  1. Create hello.go in ~/go/src/hello/ with the following code
package main
import "fmt"
func main() {
  fmt.Println("ok")
}
  1. Then go run hello.go
ok
@yingmu52
Copy link
Author

yingmu52 commented Oct 19, 2017

Create a simple http server

package main 

import "fmt"
import "net/http"

func main() {
	http.HandleFunc("/", handler)
	http.HandleFunc("/earth", handler2)
	http.ListenAndServe(":8080", nil) // `nil` means DefaultServeMux 
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello Earth")
}

func handler2(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World")
}

use go run xx.go to start the server

Create a simple TCP server

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
)

func main() {
	li, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Panic(err)
	}
	defer li.Close()

	for {
		conn, err := li.Accept()
		if err != nil {
			log.Println(err)
		}
		go handle(conn)
	}
}

func handle(conn net.Conn) {
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		ln := scanner.Text()
		fmt.Println(ln)
		fmt.Fprintf(conn, "I heard you say: %s\n", ln)
	}
	defer conn.Close()
}

@yingmu52
Copy link
Author

yingmu52 commented Oct 19, 2017

For go run xx.go not working on localhost, kill the current listening kill -9 PID

to find PID (i.e on 8080): use lsof -i tcp:8080
oneliner: lsof -P | grep ':8080' | awk '{print $2}' | xargs kill -9

@yingmu52
Copy link
Author

trailing forward slash / catches all subdirectory and execute corresponding handlers.

@yingmu52
Copy link
Author

Upload, read and store file

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
)

var content string

func main() {
	http.HandleFunc("/", next)
	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.ListenAndServe(":8080", nil)
}

func next(w http.ResponseWriter, req *http.Request) {
	var s string
	fmt.Println(req.Method)
	if req.Method == http.MethodPost {
		f, h, err := req.FormFile("q")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer f.Close()

		bs, err := ioutil.ReadAll(f)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		s = string(bs)

		// store
		dst, err := os.Create(filepath.Join("./", h.Filename))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		defer dst.Close()
		_, err = dst.Write(bs)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	io.WriteString(w, `
		<form method="POST" enctype="multipart/form-data">
		<input type="file" name="q">
		<input type="submit">
		</form>
		<br>`+s)
}

@yingmu52
Copy link
Author

yingmu52 commented Nov 1, 2017

You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int).

@yingmu52
Copy link
Author

yingmu52 commented Nov 1, 2017

Pointer Receivers are more common than value receivers

Methods with pointer receivers can modify the value to which the receiver points (as Scale does here). Since methods often need to modify their receiver, pointer receivers are more common than value receivers.

With a value receiver, the Scale method operates on a copy of the original Vertex value. (This is the same behavior as for any other function argument.) The Scale method must have a pointer receiver to change the Vertex value declared in the main function.

type Vertex struct {
	X, Y float64
}
func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
func (v Vertex) Scale1(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
func main() {
	v := Vertex{3, 4}
	v.Scale1(10)
	fmt.Println(v)
	v.Scale(10)
	fmt.Println(v)
}

Output

{3 4}
{30 40}

@yingmu52
Copy link
Author

yingmu52 commented Nov 1, 2017

Choosing a value or pointer receiver

There are two reasons to use a pointer receiver.
The first is so that the method can modify the value that its receiver points to.
The second is to avoid copying the value on each method call. This can be more efficient if the receiver is a large struct, for example.
In general, all methods on a given type should have either value or pointer receivers, but not a mixture of both.

@yingmu52
Copy link
Author

yingmu52 commented Nov 8, 2017

Waitgroup

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

func main() {
	wg := sync.WaitGroup{}

	data := make(chan int)
	wg.Add(2)
	go func() {
		for i := 0; i < 100; i++ {
			fmt.Println("Received ", <-data)
		}
		wg.Done()
	}()

	go func() {
		for i := 0; i < 100; i++ {
			data <- i
		}
		wg.Done()
	}()
	wg.Wait()
}

Buffered Channel

func main() {
	wg := sync.WaitGroup{}
	data := make(chan int, 100)
	wg.Add(2)
	go func() {
		for num := range data {
			fmt.Println("Received ", num)
		}
		wg.Done()
	}()

	go func() {
		for i := 0; i < 100; i++ {
			data <- i
		}
		close(data)
		wg.Done()
	}()
	wg.Wait()
}

Mutex

A Mutex is a mutual exclusion lock. The zero value for a Mutex is an unlocked mutex.

@yingmu52
Copy link
Author

yingmu52 commented Nov 12, 2017

Working with JSON

Marshal vs UnMarshal

type person struct {
	First string `json: "First"`
	Last  string `json: "Last"`
	Age   int    `json: "Age"`
}

func main() {
	// struct to json
	p1 := person{"james", "bond", 32}
	p2 := person{"money", "pendy", 38}
	people := []person{p1, p2}
	fmt.Println(people)
	bs, err := json.Marshal(people)
	if err != nil {
		fmt.Println(err)
	}
	jsonString := string(bs)
	fmt.Println(jsonString)

	// json to struct
	bs1 := []byte(jsonString)
	var people1 []person
	err1 := json.Unmarshal(bs1, &people1)
	if err1 != nil {
		fmt.Println(err1)
	}
	fmt.Println(people1)
}

@yingmu52
Copy link
Author

Concurrency is Not Parallelism, it is a design pattern that makes your code to run better on Multiple Core Computer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment