当前位置:  开发笔记 > 编程语言 > 正文

去做例子和习语

如何解决《去做例子和习语》经验,为你挑选了19个好方法。

没有很多Go代码可以从中学习语言,我确信我不是唯一一个尝试使用它的人.所以,如果您发现了有关该语言的有趣内容,请在此处发布示例.

我也在找

在Go中做事的惯用方法,

C/C++的思维方式"移植"到Go,

关于语法的常见缺陷,

有趣的,真的.

György Andra.. 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现在也是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)
}

看起来好老RAII(明确表示). (17认同)

+1,因为我读了很多关于Go,但我仍然没有看到这个(直到你给我看)! (4认同)

@Mike:如果你与"try:.. finally:"的块比较,LIFO以同样的方式嵌套.对于资源打开/关闭对等,这样的嵌套是唯一有意义的事情(首先打开将关闭最后). (4认同)

到底有什么好处呢? (3认同)


György Andra.. 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 }

$$

!

这更像是隐藏的功能,而不是惯用的例子 (6认同)

棒极了! (2认同)


j-g-faustus.. 22

我看到有几个人抱怨for循环,"我们为什么要i = 0; i < len; i++在这个时代说出来?".

我不同意,我喜欢for constru.如果你愿意,你可以使用长版本,但是惯用的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了很多:)



1> György Andra..:

推迟发言

"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现在也是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)
}


看起来好老RAII(明确表示).
+1,因为我读了很多关于Go,但我仍然没有看到这个(直到你给我看)!
@Mike:如果你与"try:.. finally:"的块比较,LIFO以同样的方式嵌套.对于资源打开/关闭对等,这样的嵌套是唯一有意义的事情(首先打开将关闭最后).
到底有什么好处呢?

2> György Andra..:

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 }

$$

!


这更像是隐藏的功能,而不是惯用的例子
棒极了!

3> j-g-faustus..:

我看到有几个人抱怨for循环,"我们为什么要i = 0; i < len; i++在这个时代说出来?".

我不同意,我喜欢for constru.如果你愿意,你可以使用长版本,但是惯用的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了很多:)



4> György Andra..:

这是来自Kinopiko帖子的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 (!)


请注意,分号是不必要的.

5> 小智..:
去获取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 := "/sf/ask/17360801/.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对.Read()的帮助.

这看起来相当笨重,有两个字符串和两个缓冲区,所以如果Go专家有建议,请告诉我.


围棋作者建议您"gofmt"您的代码:-)

6> Rob Russell..:

这是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

目前,开关版本对我来说看起来更干净.


哇,完全被VB扯掉了.;-)(`切换真......)

7> u0b34a0f6ae..:

您可以通过并行分配交换变量:

x, y = y, x

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

简单但有效.



8> György Andra..:

型号开关:

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");
}



9> Alvin Row..:

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

package main

import f "fmt"

func main() {
    f.Printf("Hello World\n")
}


我已经使用了这个:http://stackoverflow.com/questions/1726698/code-golf-sierpinskis-triangle/1727227#1727227

10> György Andra..:

来自James Antill的回答:

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

此外,潜在的陷阱:接收和发送运营商之间的细微差别:

a <- ch // sends ch to channel a
<-ch    // reads from channel ch


从Go 1.0.3开始,接收运算符本身**现在是一个阻塞操作.该规范已被修改:http://golang.org/ref/spec#Receive_operator.请尝试阻止行为(死锁):http://play.golang.org/p/0yurtWW4Q3

11> György Andra..:

命名结果参数

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;
}



12> György Andra..:
/* 
 * 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))
}


我建议删除问题解决网站的名称以及ID号.也许重新解释一下这个问题.至于那个绊倒它的人不会破坏这个问题.或者试图通过在网上搜索问题作弊.

13> j-g-faustus..:

我喜欢你可以根据需要重新定义类型,包括像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()幕后.



14> u0b34a0f6ae..:

返回频道

这是一个非常重要的真实习惯:如何将数据提供给频道并在之后关闭它.有了这个,你可以制作简单的迭代器(因为范围将接受一个通道)或过滤器.

// 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 x:= range chan {}循环,你会泄漏goroutine,以及它引用的所有内存.
@JeffAllen怎么样'延迟关闭(outch);`作为goroutine的第一个声明?

15> mbarkhau..:
for {
    v := <-ch
    if closed(ch) {
        break
    }
    fmt.Println(v)
}

由于range会自动检查一个封闭的通道,我们可以缩短到这个:

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



16> György Andra..:

频道读取超时:

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

从戴维斯刘被盗.



17> Scott Wales..:

有一个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来使用自动化测试工具,或者使用make install将cgo中的包和共享对象添加到$ GOROOT.



18> 小智..:

这是堆栈的实现.它说明了在类型上添加方法.

我想把它的堆栈部分变成一个切片并使用切片的属性,但是虽然我没有使用它,但我type看不到用于定义切片的语法type.

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()
}


而不是使用`fmt.Printf(...); os.Exit();`,你可以使用`panic(...)`.
它为什么有限?Go是一种托管的gc语言.您的堆栈可以根据需要进行深度调整.使用new append()builtin,它会在需要时执行类似C的realloc.

19> 小智..:

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

godoc -http=:8080

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

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有