没有很多Go代码来学习这门语言,而且我确信我不是唯一一个尝试使用它的人。所以,如果您发现了有关该语言的有趣内容,请在此处发布示例。
我也在寻找
答案 0 :(得分:35)
推迟发言
“defer”语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻。
DeferStmt =“延迟”表达。
表达式必须是函数或方法调用。每次执行“defer”语句时,都会评估函数调用的参数并重新保存,但不会调用该函数。延迟函数调用在周围函数返回之前立即以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
现在也是以exception-like方式处理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)
}
答案 1 :(得分:25)
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>
答案 2 :(得分:22)
我看到有几个人抱怨for循环,“我们为什么要在这个时代说i = 0; i < len; i++
?”。
我不同意,我喜欢for构造。如果您愿意,可以使用长版本,但惯用的Go是
var a = []int{1, 2, 3}
for i, v := range a {
fmt.Println(i, v)
}
for .. range
构造遍历所有元素并提供两个值 - 索引i
和值v
。
range
也适用于地图和频道。
但是,如果您不喜欢任何形式的for
,您可以在几行中定义each
,map
等:
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
我开始喜欢Go了很多:)
答案 3 :(得分:19)
以下是来自Kinopiko's post的iota的一个很好的例子:
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 (!)
答案 4 :(得分:19)
这是this answer的翻译。
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"))
}
感谢Scott Wales for help with .Read ().
这看起来相当笨重,有两个字符串和两个缓冲区,所以如果Go专家有建议,请告诉我。
答案 5 :(得分:18)
您可以通过并行分配交换变量:
x, y = y, x
// or in an array
a[j], a[i] = a[i], a[j]
简单但有效。
答案 6 :(得分:18)
这是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
当没有给出表达式时,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
目前,开关版本对我来说看起来更清洁。
答案 7 :(得分:17)
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");
}
答案 8 :(得分:16)
导入包时,您可以将名称重新定义为您想要的任何名称:
package main
import f "fmt"
func main() {
f.Printf("Hello World\n")
}
答案 9 :(得分:14)
命名结果参数
a的返回或结果“参数” Go函数可以给出名称和 用作常规变量,就像 传入的参数。当命名时, 它们被初始化为零 当他们的类型的价值 功能开始;如果功能 执行一个没有的return语句 参数,当前的值 结果参数用作 返回值。
名称不是强制性的,而是它们 可以使代码更短更清晰: 他们是文件。如果我们说出来的话 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;
}
答案 10 :(得分:14)
foo := <-ch // This blocks.
foo, ok := <-ch // This returns immediately.
此外,潜在的陷阱:接收和发送运营商之间的subtle difference:
a <- ch // sends ch to channel a
<-ch // reads from channel ch
答案 11 :(得分:13)
/*
* 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))
}
答案 12 :(得分:13)
我喜欢你可以根据需要重新定义类型,包括像int这样的基元,并附加不同的方法。就像定义RomanNumeral类型一样:
package main
import (
"fmt"
"strings"
)
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, " ")
var aRoman = strings.Split(numRoman, " ")
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()
调用本质上是一个强制转换,它将int类型重新定义为更具体的int类型。并Println()
在幕后调用String()
。
答案 13 :(得分:12)
这是一个非常重要的真实习惯:如何将数据输入频道并在之后将其关闭。有了这个,您可以制作简单的迭代器(因为范围将接受一个通道)或过滤器。
// 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;
}
答案 14 :(得分:11)
for {
v := <-ch
if closed(ch) {
break
}
fmt.Println(v)
}
由于范围会自动检查已关闭的频道,因此我们可以缩短至:
for v := range ch {
fmt.Println(v)
}
答案 15 :(得分:11)
频道阅读超时:
ticker := time.NewTicker(ns);
select {
case v := <- chan_target:
do_something_with_v;
case <- ticker.C:
handle_timeout;
}
Davies Liu被盗。
答案 16 :(得分:9)
您可以在$ GOROOT / src
中设置make系统使用
设置您的makefileTARG=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来使用自动化测试工具,或者使用make install将cgo中的包和共享对象添加到$ GOROOT。
答案 17 :(得分:7)
Go中另一个有趣的事情是godoc
。您可以使用
godoc -http=:8080
其中8080是端口号,golang.org上的整个网站随后在localhost:8080
处可用。
答案 18 :(得分:7)
这是堆栈的实现。它说明了在类型上添加方法。
我想将堆栈的一部分放入切片并使用切片的属性,但是虽然我在没有type
的情况下工作,但我看不到用{定义切片的语法{1}}。
type
答案 19 :(得分:4)
从中调用c代码
可以使用c运行时访问较低级别的go。
C函数的格式为
void package·function(...)
(注意点分隔符是一个unicode字符),其中参数可以是基本类型,切片,字符串等。返回值 调用
FLUSH(&ret)
(您可以返回多个值)
例如,创建一个函数
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以了解运行时中使用的示例。
另请参阅this answer以了解将c ++代码与go。
相关联答案 20 :(得分:4)
这是一个使用sqlite3包的示例。
答案 21 :(得分:3)
基于另一个答案的堆栈,但使用切片附加没有大小限制。
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()
}
答案 22 :(得分:3)
const ever = true
for ever {
// infinite loop
}
答案 23 :(得分:3)
你看过this talk了吗?它显示了很多你可以做的很酷的事情(谈话结束)
答案 24 :(得分:2)
主目录中的test
中有很多小程序。例子:
peano.go
打印阶乘。hilbert.go
有一些矩阵乘法。iota.go
有一些奇怪的iota事例。