Skip to content

Instantly share code, notes, and snippets.

@jitomesky
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jitomesky/1a463a0bfeb3ec3770a7 to your computer and use it in GitHub Desktop.
Save jitomesky/1a463a0bfeb3ec3770a7 to your computer and use it in GitHub Desktop.
A Tour of Go
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
z := float64(1.0)
for {
z_new := z - ( (z*z - x) / (2 * z))
if math.Abs(z - z_new) < 1e-12 {
break
}
z = z_new
}
return z
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(math.Sqrt(2))
}
// 配列の宣言方法
package main
import "fmt"
func main() {
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p ==", p)
for i := 0; i < len(p); i++ {
fmt.Printf("p[%d] == %d\n", i, p[i])
}
}
// makeで配列を作る
// 引数の2番目は長さ
// 引数の3番目はキャパシティ
// 配列の大きさは変えられるが、その大きさはキャパシティのサイズを超えられない
package main
import "fmt"
func main() {
a := make([]int, 5)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
c := b[:2]
printSlice("c", c)
d := c[2:5]
printSlice("d", d)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
// rangeは拡張forの様に使える
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
// rangeは拡張forの様に使える
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for _, v := range pow {
fmt.Printf("%d\n", v)
}
}
package main
import (
"code.google.com/p/go-tour/pic"
)
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8,dy)
for i:=0; i<len(pic); i++ {
pic[i] = make([]uint8,dx)
}
for yi,_ := range pic {
for xi,_ := range pic[0]{
pic[yi][xi] = uint8(xi^yi)
}
}
return pic
}
func main() {
pic.Show(Pic)
}
/*
<del>2次元配列のrangeをとると、1次元に直されて帰ってくる</del>
makeでこのように宣言すると、yが6,xが0の2次元配列として確保される
結果
0
1
2
3
4
5
*/
package main
import (
"fmt"
)
func main() {
pic := make([][]uint8,2*3)
for yi,_ := range pic {
fmt.Println(yi)
}
}
// JavaのHashMapの用に使える。newではなくmakeで作る
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
// mapの要素存在確認は、2つめの戻り値で確認する
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}
// 問題がわかりづらい
// 引数から単語を切り出して、出現回数を記録する
package main
import (
"code.google.com/p/go-tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
m := map[string]int{}
ws := strings.Fields(s)
for _,w := range(ws){
if val,ok := m[w]; ok == true{
m[w] = val + 1
}else{
m[w] = 1
}
}
return m
}
func main() {
wc.Test(WordCount)
}
// 簡単な関数なら変数に定義できる(無名関数もどき?)
package main
import (
"fmt"
"math"
)
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(3, 4))
}
// 関数クロージャー
// 関数のなかで関数を返すと、それを入れた変数を関数にして使える
// クロージャーなので、関数内の変数は保持される
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
fn1 := 0
fn2 := 1
return func() int {
fn := fn1
fn1 = fn2
fn2 = fn + fn1
return fn
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
// switch
// breakはいらない。fallthroughをつけるとスルーできる
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.", os)
}
}
// Output
// (1.2599210498948732+0i)
// (2+0i)
package main
import (
"fmt"
"math/cmplx"
)
func Cbrt(x complex128) complex128 {
z := complex128(1.0)
for diff := complex128(1.0); cmplx.Abs(diff) > 1e-10; {
diff = (cmplx.Pow(z,3) - x) / (3 * cmplx.Pow(z,2))
z -= diff
}
return z
}
func main() {
fmt.Println(Cbrt(2))
fmt.Println(cmplx.Pow(Cbrt(2),3))
}
// クラスはないので、structでメソッドを定義する
// 引数に(v *Vertex)をとることで、Vertex構造体のメソッドに慣れる?
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
// 実際には、自分で定義した型であれば、メソッドを定義できる
// 実質的なクラスの作り方はこれ?
package main
import (
"fmt"
"math"
)
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
}
// (v *Vertex)はポインタ参照なので値を変更できる
// (v Vertex)は値参照なので、読むことはできるが、変更を反映できない
package main
import (
"fmt"
"math"
)
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) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
v.Scale(5)
fmt.Println(v, v.Abs())
}
// インターフェース型は、そこに列挙したメソッドが実装された値(structやtype)を入れられる
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
// In the following line, v is a Vertex (not *Vertex)
// and does NOT implement Abser.
a = v
fmt.Println(a.Abs())
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// エラーはErrorメソッドを実装すればよい
package main
import (
"fmt"
"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",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string{
return fmt.Sprintf("cannot Sqrt negative number: %f",float64(e))
}
func Sqrt(f float64) (float64, error) {
if f < 0.0 {
return 0.0, ErrNegativeSqrt(f)
}
z := float64(1.0)
for {
z_new := z - ( (z*z - f) / (2 * z))
if math.Abs(z - z_new) < 1e-12 {
break
}
z = z_new
}
return z, nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
package main
import (
"code.google.com/p/go-tour/pic"
"image"
"image/color"
)
type Image struct{
w,h int
}
func (r *Image) Bounds() image.Rectangle {
return image.Rect(0, 0, r.w, r.h)
}
func (r *Image) ColorModel() color.Model {
return color.RGBAModel
}
func (r *Image) At(x, y int) color.Color {
return color.RGBA{uint8(x), uint8(y), 255, 255}
}
func main() {
m := &Image{256,256}
pic.ShowImage(m)
}
package main
import (
"io"
"os"
"strings"
"unicode"
)
type rot13Reader struct {
r io.Reader
}
func (rot *rot13Reader) Read(p []byte) (n int, err error){
n, err = rot.r.Read(p)
for i,c := range(p){
if unicode.IsLetter(rune(c)) {
base := byte('a')
if(unicode.IsUpper(rune(c))) {
base = byte('A')
}
diff := c - base
diff = (diff + 13) % 26
p[i] = base + diff
}
}
return n,err
}
func main() {
s := strings.NewReader(
"Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
// goをつけてメソッド呼び出しすればスレッドで処理できる
package main
import (
"fmt"
"time"
)
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 "fmt"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum 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)
}
// 送信側はclose()で送信の終了を明示的に示せる
// 送信の終了は第2パラメータでチェックできる
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)
}
}
// Tips: フィボナッチ数の計算は、以下の様に一括でかける
// select構文はswitchのgoroutine版?
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 main
import (
"code.google.com/p/go-tour/tree"
"fmt"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int){
if t != nil {
_walk(t, ch)
}
close(ch)
}
func _walk(t *tree.Tree, ch chan int){
if t == nil {
return
}
// 左から深さ優先で調べていかないと、整合性がとれない
_walk(t.Left,ch)
ch <- t.Value
_walk(t.Right,ch)
return
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool{
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for c1 := range ch1 {
c2 := <- ch2
if c1 != c2 {
return false
}
}
// ch1よりch2の要素が多い場合もエラー
if _, ok := <- ch2 ; ok {
return false
}
return true
}
func main() {
/*
ch := make(chan int, 10)
go Walk(tree.New(1), ch)
for i := range ch{
fmt.Println(i)
}
*/
if test1 := Same(tree.New(1), tree.New(1)) ; test1 == true {
fmt.Println("correct!")
}else{
fmt.Println("incorrect...")
}
if test2 := Same(tree.New(1), tree.New(2)) ; test2 == false {
fmt.Println("correct!")
}else{
fmt.Println("incorrect...")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment