去例子和成语

学习语言的Go代码并不多,而且我确定我不是唯一一个用这个语言进行实验的人。 所以,如果你发现了一些关于该语言的有趣的东西,请在这里发表一个例子。

我也在找

  • 在Go中做事的惯用方式,
  • C / C ++思维“移植”到Go,
  • 语法常见的陷阱,
  • 真的很有意思

延迟陈述

“延迟”语句调用执行延迟到周围函数返回时的函数。

DeferStmt =“推迟”expression式。

expression式必须是函数或方法调用。 每次执行“延迟”语句时,都会重新评估和保存函数调用的参数,但不调用该函数。 延迟函数调用紧接在周围函数返回之前以LIFO顺序执行,但是在返回值(如果有)已经被评估之后。

lock(l); defer unlock(l); // unlocking happens before surrounding function returns // prints 3 2 1 0 before surrounding function returns for i := 0; i <= 3; i++ { defer fmt.Print(i); } 

更新:

defer现在也是以一种例外的方式处理panic的惯用方式:

 package main import "fmt" func main() { f() fmt.Println("Returned normally from f.") } func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() fmt.Println("Calling g.") g(0) fmt.Println("Returned normally from g.") } func g(i int) { if i > 3 { fmt.Println("Panicking!") panic(fmt.Sprintf("%v", i)) } defer fmt.Println("Defer in g", i) fmt.Println("Printing in g", i) g(i+1) } 

Go目标文件实际上包含一个明文标题:

 jurily@jurily ~/workspace/go/euler31 $ 6g euler31.go jurily@jurily ~/workspace/go/euler31 $ cat euler31.6 amd64 exports automatically generated from euler31.go in package "main" import $$ // exports package main var main.coin [9]int func main.howmany (amount int, max int) (? int) func main.main () var main.initdone· uint8 func main.init () $$ // local types type main.dsigddd_1·1 struct { ? int } $$ ! <binary segment> 

我看到有几个人抱怨这个循环,就像“为什么我们不得不在这个时代说i = 0; i < len; i++在这个时代呢?

我不同意,我喜欢这个构造。 如果你愿意,你可以使用长版本,但是习惯性的Go是

 var a = []int{1,2,3}; for i, v := range a { fmt.Println(i, v); } 

for .. range构造遍历所有元素并提供两个值 – 索引i和值v

range也适用于地图和频道。

不过,如果你不喜欢任何forms,你可以在几行中定义eachmap等:

 type IntArr []int // 'each' takes a function argument. // The function must accept two ints, the index and value, // and will be called on each element in turn. func (a IntArr) each(fn func(index, value int)) { for i, v := range a { fn(i, v); } } func main() { var a = IntArr([]int{2,0,0,9}); // create int slice and cast to IntArr var fnPrint = func (i, v int) { fmt.Println(i, ":", v); }; // create a function a.each(fnPrint); // call on each element } 

版画

 0 : 2 1 : 0 2 : 0 3 : 9 

我开始喜欢去很多:)

去获得你的stackoverflow声誉

这是这个答案的翻译。

 package main import ( "json" "fmt" "http" "os" "strings" ) func die(message string) { fmt.Printf("%s.\n", message); os.Exit(1); } func main() { kinopiko_flair := "https://stackoverflow.com/users/flair/181548.json" response, _, err := http.Get(kinopiko_flair) if err != nil { die(fmt.Sprintf("Error getting %s", kinopiko_flair)) } var nr int const buf_size = 0x1000 buf := make([]byte, buf_size) nr, err = response.Body.Read(buf) if err != nil && error != os.EOF { die(fmt.Sprintf("Error reading response: %s", err.String())) } if nr >= buf_size { die ("Buffer overrun") } response.Body.Close() json_text := strings.Split(string(buf), "\000", 2) parsed, ok, errtok := json.StringToJson(json_text[0]) if ! ok { die(fmt.Sprintf("Error parsing JSON %s at %s", json_text, errtok)) } fmt.Printf("Your stackoverflow.com reputation is %s\n", parsed.Get ("reputation")) } 

感谢斯科特威尔士求助于.Read()。

这看起来相当笨重,两个string和两个缓冲区,所以如果任何专家有build议,让我知道。

这是Kinopiko的post里的一个很好的例子:

 type ByteSize float64 const ( _ = iota; // ignore first value by assigning to blank identifier KB ByteSize = 1<<(10*iota) MB GB TB PB YB ) // This implicitly repeats to fill in all the values (!) 

这里有一个来自Effective Go页面的成语

 switch { case '0' <= c && c <= '9': return c - '0' case 'a' <= c && c <= 'f': return c - 'a' + 10 case 'A' <= c && c <= 'F': return c - 'A' + 10 } return 0 

当没有给出expression式时,switch语句开启true。 所以这相当于

 if '0' <= c && c <= '9' { return c-'0'; } else if 'a' <= c && c <= 'f' { return c - 'a' + 10; } else if 'A' <= c && c <= 'F' { return c - 'A' + 10; } return 0; 

目前,开关版本看起来更清洁。

您可以通过并行赋值交换variables:

 x, y = y, x // or in an array a[j], a[i] = a[i], a[j] 

简单而有效。

types开关 :

 switch i := x.(type) { case nil: printString("x is nil"); case int: printInt(i); // i is an int case float: printFloat(i); // i is a float case func(int) float: printFunction(i); // i is a function case bool, string: printString("type is bool or string"); // i is an interface{} default: printString("don't know the type"); } 

导入包时,可以重新定义名称为任何你想要的:

 package main import f "fmt" func main() { f.Printf("Hello World\n"); } 

命名结果参数

Go函数的返回值或结果“参数”可以被赋予名称,并用作常规variables,就像传入的参数一样。 当命名时,它们在函数开始时被初始化为它们types的零值; 如果函数执行一个不带参数的返回语句,那么结果参数的当前值被用作返回值。

这些名字并不是强制性的,但是它们可以使代码更简洁明了:它们是文档。 如果我们命名nextInt的结果,那么显而易见的是返回int是哪个。

 func nextInt(b []byte, pos int) (value, nextPos int) { 

由于命名的结果被初始化,并被绑定到一个没有经验的返回,他们可以简化和澄清。 以下是使用它们的io.ReadFull版本:

 func ReadFull(r Reader, buf []byte) (n int, err os.Error) { for len(buf) > 0 && err == nil { var nr int; nr, err = r.Read(buf); n += nr; buf = buf[nr:len(buf)]; } return; } 

从James Antill的回答 :

 foo := <-ch; // This blocks. foo, ok := <-ch; // This returns immediately. 

此外,还有一个潜在的缺陷:接收和发送操作员之间的细微差别 :

 a <- ch; // sends ch to channel a <-ch; // reads from channel ch 
 /* * How many different ways can £2 be made using any number of coins? * Now with 100% less semicolons! */ package main import "fmt" /* This line took me over 10 minutes to figure out. * "[...]" means "figure out the size yourself" * If you only specify "[]", it will try to create a slice, which is a reference to an existing array. * Also, ":=" doesn't work here. */ var coin = [...]int{0, 1, 2, 5, 10, 20, 50, 100, 200} func howmany(amount int, max int) int { if amount == 0 { return 1 } if amount < 0 { return 0 } if max <= 0 && amount >= 1 { return 0 } // recursion works as expected return howmany(amount, max-1) + howmany(amount-coin[max], max) } func main() { fmt.Println(howmany(200, len(coin)-1)) } 

我喜欢你可以重新定义types,包括象int这样的基本types,只要你喜欢,并附上不同的方法。 就像定义一个RomanNumeraltypes一样:

 var numText = "zero one two three four five six seven eight nine ten" var numRoman = "- I II III IV V VI VII IX X" var aText = strings.Split(numText, " ", 0) var aRoman = strings.Split(numRoman, " ", 0) type TextNumber int type RomanNumber int func (n TextNumber) String() string { return aText[n]; } func (n RomanNumber) String() string { return aRoman[n]; } func main() { var i = 5; fmt.Println("Number: ", i, TextNumber(i), RomanNumber(i)); } 

打印出来

 Number: 5 five V 

RomanNumber()调用本质上是一个RomanNumber() ,它将inttypes重新定义为更具体的inttypes。 和Println()在幕后调用String()

返回一个频道

这是一个非常重要的真实习惯用法,那就是如何将数据提供给频道,然后closures频道。 有了这个,你可以做简单的迭代器(因为范围将接受一个通道)或filter。

 // return a channel that doubles the values in the input channel func DoublingIterator(input chan int) chan int { outch := make(chan int); // start a goroutine to feed the channel (asynchronously) go func() { for x := range input { outch <- 2*x; } // close the channel we created and control close(outch); }(); return outch; } 
 for { v := <-ch; if closed(ch) { break } fmt.Println(v) } 

由于范围自动检查一个封闭的频道,我们可以缩短到这个:

 for v := range ch { fmt.Println(v) } 

通道读取超时:

 ticker := time.NewTicker(ns); select { case v := <- chan_target: do_something_with_v; case <- ticker.C: handle_timeout; } 

刘从刘被盗。

有一个make系统可以在$ GOROOT / src中使用

设置你的makefile

 TARG=foobar # Name of package to compile GOFILES=foo.go bar.go # Go sources CGOFILES=bang.cgo # Sources to run cgo on OFILES=a_c_file.$O # Sources compiled with $Oc # $O is the arch number (6 for x86_64) include $(GOROOT)/src/Make.$(GOARCH) include $(GOROOT)/src/Make.pkg 

然后可以通过运行make test来使用自动化testing工具,或者使用make install将cgo中的包和共享对象添加到$ GOROOT中。

这是一个堆栈的实现。 它演示了向types添加方法。

我想把堆栈的一部分放到一个slice中,然后使用这个slice的属性,但是虽然没有这个type ,但是我看不到用type定义一个slice的语法。

 package main import "fmt"; import "os"; const stack_max = 100; type Stack2 struct { stack [stack_max]string; size int; }; func (s *Stack2) push (pushed_string string) { n := s.size; if n >= stack_max - 1 { fmt.Print ("Oh noes\n"); os.Exit (1); } s.size++; s.stack[n] = pushed_string } func (s *Stack2) pop () string { n := s.size; if n == 0 { fmt.Print ("Underflow\n"); os.Exit (1); } top := s.stack[n-1]; s.size--; return top; } func (s *Stack2) print_all () { n := s.size; fmt.Printf ("Stack size is %d\n", n); for i := 0; i < n; i++ { fmt.Printf ("%d:\t%s\n", i, s.stack[i]); } } func main () { stack := new (Stack2); stack.print_all (); stack.push ("boo"); stack.print_all (); popped := stack.pop (); fmt.Printf ("Stack top is %s\n", popped); stack.print_all (); stack.push ("moo"); stack.push ("zoo"); stack.print_all (); popped2 := stack.pop (); fmt.Printf ("Stack top is %s\n", popped2); stack.print_all (); } 

Go的另一个有趣的事情就是godoc 。 您可以在计算机上使用它作为Web服务器运行

 godoc -http=:8080 

其中8080​​是端口号,golang.org上的整个网站可以在localhost:8080

从Go调用c代码

可以通过使用c运行时访问较低级别的进程。

C函数的forms

 void package·function(...) 

(注意点分隔符是一个Unicode字符)参数可能是基本的types,切片,string等。要返回值调用

 FLUSH(&ret) 

(你可以返回多个值)

例如,创build一个函数

 package foo bar( a int32, b string )(c float32 ){ c = 1.3 + float32(a - int32(len(b)) } 

在C你使用

 #include "runtime.h" void foo·bar(int32 a, String b, float32 c){ c = 1.3 + a - b.len; FLUSH(&c); } 

请注意,您仍然应该将该函数声明为go文件,并且您必须自己处理内存。 我不确定是否可以使用这个调用外部库,使用cgo可能会更好。

查看运行时中使用的示例$ GOROOT / src / pkg / runtime。

另请参阅将c ++代码与go关联的答案 。

你有看这个演讲吗? 它显示了很多很酷的东西,你可以做(​​谈话结束)

 const ever = true; for ever { //infinite loop } 

这是一个使用sqlite3包的例子。

http://github.com/bikal/gosqlite-example

基于另一个答案,但使用切片追加的堆栈没有大小限制。

 package main import "fmt" import "os" type Stack2 struct { // initial storage space for the stack stack [10]string cur []string } func (s *Stack2) push(pushed_string string) { s.cur = append(s.cur, pushed_string) } func (s *Stack2) pop() (popped string) { if len(s.cur) == 0 { fmt.Print("Underflow\n") os.Exit(1) } popped = s.cur[len(s.cur)-1] s.cur = s.cur[0 : len(s.cur)-1] return } func (s *Stack2) print_all() { fmt.Printf("Stack size is %d\n", len(s.cur)) for i, s := range s.cur { fmt.Printf("%d:\t%s\n", i, s) } } func NewStack() (stack *Stack2) { stack = new(Stack2) // init the slice to an empty slice of the underlying storage stack.cur = stack.stack[0:0] return } func main() { stack := NewStack() stack.print_all() stack.push("boo") stack.print_all() popped := stack.pop() fmt.Printf("Stack top is %s\n", popped) stack.print_all() stack.push("moo") stack.push("zoo") stack.print_all() popped2 := stack.pop() fmt.Printf("Stack top is %s\n", popped2) stack.print_all() } 

主目录中有很多小程序正在test中。 例子:

  • peano.go打印阶乘。
  • hilbert.go有一些matrix乘法。
  • iota.go有奇怪的iota的事例。