Skip to content

Instantly share code, notes, and snippets.

@ruandao
Created July 16, 2016 20:14
Show Gist options
  • Select an option

  • Save ruandao/0c36d2eca2fb0ccfdb2bcb802b0f773e to your computer and use it in GitHub Desktop.

Select an option

Save ruandao/0c36d2eca2fb0ccfdb2bcb802b0f773e to your computer and use it in GitHub Desktop.
golang tour finished
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<- ch)
}
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c
fmt.Println(x, y, x+y)
}
package main
import (
"time"
"fmt"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <- boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
package main
import (
"golang.org/x/tour/tree"
"fmt"
)
type Tree struct {
Left *Tree
Value int
Right *Tree
}
func EqualTree(t1, t2 *Tree) bool {
if t1 == t2 {
return true
}
if t1 == nil || t2 == nil {
return false
}
if t1.Value != t2.Value {
return false
}
return EqualTree(t1.Left, t2.Left) &&
EqualTree(t1.Right, t2.Right)
}
/*
t shouldn't be nil
*/
func walkRecurse(t *tree.Tree, ch chan int) {
if t == nil {
return
}
ch <- t.Value
walkRecurse(t.Left, ch)
walkRecurse(t.Right, ch)
}
func Walk(t *tree.Tree, ch chan int) {
walkRecurse(t, ch)
close(ch)
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
if t1 == t2 {
return true
}
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
v1, ok1 := <- ch1
v2, ok2 := <- ch2
fmt.Printf("%v %v\n", v1, v2)
if v1 != v2 || ok1 != ok2 {
return false
}
if ok1 {
return true
}
}
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(10), tree.New(4)))
}
package main
import (
"fmt"
"time"
"sync"
)
type Fetcher interface {
// Fetch returns the body of URL and
// a slice of URLs found on that page.
Fetch(url string) (body string, urls []string, err error)
}
type fetchObj struct {
url string
depth int
}
type MutexMap struct {
m sync.Mutex
urlCount map[string]int
}
func (mm *MutexMap)Inc(key string) int {
mm.m.Lock()
defer mm.m.Unlock()
mm.urlCount[key]++
count := mm.urlCount[key]
return count
}
var mutexM = &MutexMap{urlCount: make(map[string]int)}
func craw(fo fetchObj, urlChan chan fetchObj, remainderChan chan int) {
defer func() {
remainderChan <- -1
}()
if fo.depth == 0 {
return
}
if mutexM.Inc(fo.url) > 1 {
return
}
body, urls, err := fetcher.Fetch(fo.url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", fo.url, body)
for _, url := range urls {
urlChan <- fetchObj{url, fo.depth - 1}
remainderChan <- 1
}
}
// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
// TODO: Fetch URLs in parallel
// TODO: Don't fetch the same URL twice.
// This implementation doesn't do either
defer fmt.Println("end")
urlChan := make(chan fetchObj)
remainderChan := make(chan int)
fo := fetchObj{url, depth}
count := 1
go craw(fo, urlChan, remainderChan)
for {
select {
case fo = <- urlChan:
go craw(fo, urlChan, remainderChan)
case change := <- remainderChan:
count += change
if count == 0 {
return
}
default:
time.Sleep(100 * time.Millisecond)
}
}
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
// fakeFetcher is Fetcher that return canned results.
type fakeFetcher map[string]*fakeResult
type fakeResult struct {
body string
urls []string
}
func (f fakeFetcher) Fetch(url string) (string, []string, error) {
if res, ok := f[url]; ok {
return res.body, res.urls, nil
}
return "", nil, fmt.Errorf("not found: %s", url)
}
// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
"http://golang.org/": &fakeResult{
"The Go Programming Language",
[]string{
"http://golang.org/pkg/",
"http://golang.org/cmd/",
},
},
"http://golang.org/pkg/": &fakeResult{
"Packages",
[]string{
"http://golang.org/",
"http://golang.org/cmd/",
"http://golang.org/pkg/fmt/",
"http://golang.org/pkg/os/",
},
},
"http://golang.org/pkg/fmt/": &fakeResult{
"Package fmt",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
"http://golang.org/pkg/os/": &fakeResult{
"Package os",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
}
package main
import (
"time"
"fmt"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
package main
import (
"sync"
"time"
"fmt"
)
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
defer c.mux.Unlock()
c.v[key]++
}
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}
package main
import "fmt"
func fibonacci(n int, c chan int) {
x, y := 0, 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)
}
}
package methods
import (
"fmt"
"math"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s", e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
type ErrNegativeSqrt struct {
srcValue float64
}
func (e *ErrNegativeSqrt) Error() string {
return fmt.Sprintf("negative value: %v don't have Sqrt", e.srcValue)
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return 0, &ErrNegativeSqrt{x}
}
return math.Sqrt(x), nil
}
package methods
import (
"strings"
"testing"
)
func TestMyError_Error(t *testing.T) {
if err := run(); err != nil {
if strings.EqualFold(err.Error(), "it didn't work") {
t.Errorf("err should return %q", "it didn't work")
}
}
}
func TestErrNegativeSqrt_Error(t *testing.T) {
if _, err := Sqrt(-203); err == nil {
t.Error("Sqrt(-203) should return err")
}
if _, err := Sqrt(64); err != nil {
t.Error("Sqrt(64) should not return err")
}
}
package methods
import (
"image/color"
"image"
)
type Image struct {
}
func (img *Image)ColorModel() color.Model {
return color.RGBAModel
}
func (img *Image) Bounds() image.Rectangle {
return image.Rect(0, 0, 100, 100)
}
func (img *Image) At(x, y int) color.Color {
r := 100 / 2
borderWidth := 2
x, y = x - r, y - r
x2 := x*x
y2 := y*y
minR2 := (r-borderWidth/2) * (r-borderWidth/2)
maxR2 := (r+borderWidth/2) * (r+borderWidth/2)
if x2 + y2 >= minR2 && x2 + y2 <= maxR2 {
return color.RGBA{255,255,255,255}
}
return color.RGBA{100, 100, 255, 255}
}
package methods
import (
"testing"
"golang.org/x/tour/pic"
)
func TestImage(t *testing.T) {
m := Image{}
pic.ShowImage(&m)
}
package methods
import (
"io"
)
type MyReader struct {
}
func (my *MyReader) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, io.ErrShortBuffer
}
for i := range b {
b[i] = 'A'
}
return len(b), nil
}
package methods
import (
"golang.org/x/tour/reader"
"testing"
)
func TestMyReader_Read(t *testing.T) {
reader.Validate(&MyReader{})
}
package methods
import (
"io"
)
type rot13Reader struct {
r io.Reader
}
func (rot *rot13Reader) Read(b []byte) (int, error) {
n, err := rot.r.Read(b)
if err != nil {
return n, err
}
for i := 0; i < n; i++ {
b[i] = rot13(b[i])
}
return n, nil
}
func rot13(b byte) byte {
if (b >= 'A' && b < 'N') || (b >='a' && b < 'n') {
b += 13
} else if (b > 'M' && b <= 'Z') || (b > 'm' && b <= 'z'){
b -= 13
}
return b
}
package methods
import (
"testing"
"strings"
"io"
"os"
)
func TestRot13Reader_Read(t *testing.T) {
s := strings.NewReader("Lbh penpxrq gur phqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
package methods
import "fmt"
type Abser interface {
Abs() float64
}
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
package methods
import "testing"
import (
"fmt"
"math"
"strings"
)
func TestVertex_Abs2(t *testing.T) {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
a.Abs()
}
func do(i interface{}) string {
switch v := i.(type) {
case int:
return fmt.Sprintf("Twice %v is %v\n", v, v*2)
case string:
return fmt.Sprintf("%q is %v bytes long\n", v, len(v))
default:
return fmt.Sprintf("I don't know about type %T!\n", v)
}
}
func Test_do(t *testing.T) {
if s := do(21); strings.EqualFold(s, "Twice 21 is 42\\n") {
t.Errorf("do(21) not return 'Twice 21 is 42\\n' %v'", s)
}
if s := do("hello"); strings.EqualFold(s, "'hello' is 5 bytes long\n") {
t.Error("do('hello') error")
}
if s := do(true); strings.EqualFold(s, "I don't know about type bool!\\n") {
t.Errorf("do(true) %v", s)
}
}
package methods
import (
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
package methods
import (
"math"
"testing"
)
func TestVertex_Abs(t *testing.T) {
v := Vertex{3, 4}
if v.Abs() != 5 {
t.Error("Vertex{3, 4}.Abs() != 5")
}
}
func TestMyFloat_Abs(t *testing.T) {
f := MyFloat(-math.Sqrt2)
if f.Abs() != math.Sqrt2 {
t.Error("MyFloat(-math.Sqrt2).Abs() != math.Sqrt2")
}
}
func TestVertex_Scale(t *testing.T) {
v := Vertex{3, 4}
v.Scale(10)
expect := 50.0
if v.Abs() != expect {
t.Errorf("Vertex{3, 4} after scale(10) .Abs() = %v != %v", v.Abs(), expect)
}
}
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 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)
}
package methods
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
package methods
import (
"fmt"
"testing"
"strings"
)
type IPAddr [4]byte
func (ip IPAddr) String() string {
return fmt.Sprintf("%v.%v.%v.%v",
int(ip[0]),
int(ip[1]),
int(ip[2]),
int(ip[3]),
)
}
func TestIPAddr(t *testing.T) {
hosts := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
expectedResult := map[string]string {
"loopback": "127.0.0.1",
"googleDNS": "8.8.8.8",
}
for name, ip := range hosts {
expectedIP := expectedResult[name]
if !strings.EqualFold(expectedIP, ip.String()) {
t.Errorf("name: %v result: %v expect: %v", name, ip, expectedIP)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment