Go示例和惯用语

huangapple go评论112阅读模式
英文:

Go examples and idioms

问题

有很少的Go代码可以学习这门语言,我相信我不是唯一一个在尝试使用它的人。所以,如果你发现了关于这门语言的有趣的东西,请在这里发布一个例子。

我还在寻找:

  • 在Go中完成事情的惯用方式,
  • 将C/C++的思维方式“移植”到Go中,
  • 关于语法的常见陷阱,
  • 任何有趣的东西。
英文:

There's not a lot of Go code to learn the language from, and I'm sure I'm not the only one experimenting with it. So, if you found out something interesting about the language, please post an example here.

I'm also looking for

  • idiomatic ways to do things in Go,
  • C/C++ style of thinking "ported" to Go,
  • common pitfalls about the syntax,
  • anything interesting, really.

答案1

得分: 35

延迟语句

>一个"defer"语句会调用一个在周围函数返回时被延迟执行的函数。
>
>DeferStmt = "defer" Expression .
>
>表达式必须是一个函数或方法调用。每次"defer"语句执行时,函数调用的参数会被重新评估和保存,但函数不会被调用。延迟函数调用会在周围函数返回之前按照后进先出的顺序执行,但在返回值(如果有的话)被评估之后执行。

<br/>

lock(l);
defer unlock(l);  // 解锁在周围函数返回之前发生

// 在周围函数返回之前打印 3 2 1 0
for i := 0; i &lt;= 3; i++ {
    defer fmt.Print(i);
}

更新:

defer现在也是以类似异常的方式处理panic的惯用方法:

package main

import "fmt"

func main() {
    f()
    fmt.Println("从 f 正常返回。")
}

func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("在 f 中恢复", r)
        }
    }()
    fmt.Println("调用 g。")
    g(0)
    fmt.Println("从 g 正常返回。")
}

func g(i int) {
    if i > 3 {
        fmt.Println("发生恐慌!")
        panic(fmt.Sprintf("%v", i))
    }
    defer fmt.Println("在 g 中延迟", i)
    fmt.Println("在 g 中打印", i)
    g(i+1)
}
英文:

<b>Defer statements</b>

>A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns.
>
>DeferStmt = "defer" Expression .
>
>The expression must be a function or method call. Each time the "defer" statement executes, the parameters to the function call are evaluated and saved anew but the function is not invoked. Deferred function calls are executed in LIFO order immediately before the surrounding function returns, but after the return values, if any, have been evaluated.

<br/>

lock(l);
defer unlock(l);  // unlocking happens before surrounding function returns

// prints 3 2 1 0 before surrounding function returns
for i := 0; i &lt;= 3; i++ {
    defer fmt.Print(i);
}

Update:

defer is now also the idiomatic way to handle panic in an exception-like manner:

package main

import &quot;fmt&quot;

func main() {
    f()
    fmt.Println(&quot;Returned normally from f.&quot;)
}

func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(&quot;Recovered in f&quot;, r)
        }
    }()
    fmt.Println(&quot;Calling g.&quot;)
    g(0)
    fmt.Println(&quot;Returned normally from g.&quot;)
}

func g(i int) {
    if i &gt; 3 {
        fmt.Println(&quot;Panicking!&quot;)
        panic(fmt.Sprintf(&quot;%v&quot;, i))
    }
    defer fmt.Println(&quot;Defer in g&quot;, i)
    fmt.Println(&quot;Printing in g&quot;, i)
    g(i+1)
}

答案2

得分: 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>
英文:

Go object files actually include a cleartext header:

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 &quot;main&quot;
    import

$$  // exports
  package main
    var main.coin [9]int
    func main.howmany (amount int, max int) (? int)
    func main.main ()
    var main.initdone&#183; uint8
    func main.init ()

$$  // local types
  type main.dsigddd_1&#183;1 struct { ? int }

$$

!
&lt;binary segment&gt;

答案3

得分: 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,你可以用几行代码定义eachmap等:

type IntArr []int

// 'each'接受一个函数参数。
// 函数必须接受两个int参数,即索引和值,
// 并将在每个元素上调用。
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}) // 创建int切片并转换为IntArr
	var fnPrint = func(i, v int) {
		fmt.Println(i, ":", v)
	} // 创建一个函数

	a.each(fnPrint) // 对每个元素调用
}

输出

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

我开始非常喜欢Go Go示例和惯用语

英文:

I have seen a couple of people complaining about the for-loop, along the lines of "why should we have to say i = 0; i &lt; len; i++ in this day and age?".

I disagree, I like the for construct. You can use the long version if you wish, but the idiomatic Go is

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

The for .. range construct loops over all the elements and supplies two values - the index i and the value v.

range also works on maps and channels.

Still, if you dislike for in any form, you can define each, map etc. in a few lines:

type IntArr []int

// &#39;each&#39; 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, &quot;:&quot;, v)
	} // create a function

	a.each(fnPrint) // call on each element
}

prints

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

I'm starting to like Go a lot Go示例和惯用语

答案4

得分: 19

这是一个关于 iota 的好例子,来自 Kinopiko 的帖子

type ByteSize float64
const (
    _ = iota;   // 通过赋值给空白标识符忽略第一个值
    KB ByteSize = 1<<(10*iota)
    MB
    GB
    TB
    PB
    YB
)

// 这个隐式地重复以填充所有的值 (!)
英文:

Here's a nice example of iota from Kinopiko's post:

type ByteSize float64
const (
    _ = iota;   // ignore first value by assigning to blank identifier
    KB ByteSize = 1&lt;&lt;(10*iota)
    MB
    GB
    TB
    PB
    YB
)

// This implicitly repeats to fill in all the values (!)

答案5

得分: 19

去获取你的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("获取%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("读取响应时出错:%s", err.String()))
    }
    if nr >= buf_size { die ("缓冲区溢出") }
    response.Body.Close()

    json_text := strings.Split(string(buf), "
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("获取%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("读取响应时出错:%s", err.String()))
}
if nr >= buf_size { die ("缓冲区溢出") }
response.Body.Close()
json_text := strings.Split(string(buf), "\000", 2)
parsed, ok, errtok := json.StringToJson(json_text[0])
if ! ok {
die(fmt.Sprintf("解析JSON %s 时出错:%s", json_text, errtok))
}
fmt.Printf("你的stackoverflow.com声望是 %s\n", parsed.Get ("reputation"))
}
0", 2) parsed, ok, errtok := json.StringToJson(json_text[0]) if ! ok { die(fmt.Sprintf("解析JSON %s 时出错:%s", json_text, errtok)) } fmt.Printf("你的stackoverflow.com声望是 %s\n", parsed.Get ("reputation")) }

感谢Scott Wales对.Read()的帮助

这看起来还是有些笨拙,有两个字符串和两个缓冲区,所以如果有任何Go专家有建议,请告诉我。

英文:

Go and get your stackoverflow reputation

This is a translation of this answer.

package main

import (
    &quot;json&quot;
    &quot;fmt&quot;
    &quot;http&quot;
    &quot;os&quot;
    &quot;strings&quot;
)

func die(message string) {
    fmt.Printf(&quot;%s.\n&quot;, message);
    os.Exit(1);
}

func main() {
    kinopiko_flair := &quot;https://stackoverflow.com/users/flair/181548.json&quot;
    response, _, err := http.Get(kinopiko_flair)
    if err != nil {
        die(fmt.Sprintf(&quot;Error getting %s&quot;, kinopiko_flair))
    }

    var nr int
    const buf_size = 0x1000
    buf := make([]byte, buf_size)

    nr, err = response.Body.Read(buf)
    if err != nil &amp;&amp; error != os.EOF {
        die(fmt.Sprintf(&quot;Error reading response: %s&quot;, err.String()))
    }
    if nr &gt;= buf_size { die (&quot;Buffer overrun&quot;) }
    response.Body.Close()

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

Thanks to Scott Wales for help with .Read ().

This looks fairly clunky still, with the two strings and two buffers, so if any Go experts have advice, let me know.

答案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

目前来看,switch版本对我来说更加简洁。

英文:

Here's an idiom from the Effective Go page

switch {
case &#39;0&#39; &lt;= c &amp;&amp; c &lt;= &#39;9&#39;:
	return c - &#39;0&#39;
case &#39;a&#39; &lt;= c &amp;&amp; c &lt;= &#39;f&#39;:
	return c - &#39;a&#39; + 10
case &#39;A&#39; &lt;= c &amp;&amp; c &lt;= &#39;F&#39;:
	return c - &#39;A&#39; + 10
}
return 0

The switch statement switches on true when no expression is given. So this is equivalent to

if &#39;0&#39; &lt;= c &amp;&amp; c &lt;= &#39;9&#39; {
	return c - &#39;0&#39;
} else if &#39;a&#39; &lt;= c &amp;&amp; c &lt;= &#39;f&#39; {
	return c - &#39;a&#39; + 10
} else if &#39;A&#39; &lt;= c &amp;&amp; c &lt;= &#39;F&#39; {
	return c - &#39;A&#39; + 10
}
return 0

At the moment, the switch version looks a little cleaner to me.

答案7

得分: 18

你可以通过并行赋值来交换变量:

x, y = y, x

// 或者在数组中
a[j], a[i] = a[i], a[j]

简单而有效。

英文:

You can swap variables by parallel assignment:

x, y = y, x

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

simple but effective.

答案8

得分: 17

类型切换:

switch i := x.(type) {
case nil:
    printString("x 是 nil");
case int:
    printInt(i);  // i 是一个整数
case float:
    printFloat(i);  // i 是一个浮点数
case func(int) float:
    printFunction(i);  // i 是一个函数
case bool, string:
    printString("类型是 bool 或 string");  // i 是一个接口{}
default:
    printString("不知道类型");
}
英文:

Type switches:

switch i := x.(type) {
case nil:
    printString(&quot;x is nil&quot;);
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(&quot;type is bool or string&quot;);  // i is an interface{}
default:
    printString(&quot;don&#39;t know the type&quot;);
}

答案9

得分: 16

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

package main

import f "fmt"

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

When importing packages, you can redefine the name to anything you want:

package main

import f &quot;fmt&quot;

func main() {
	f.Printf(&quot;Hello World\n&quot;)
}

答案10

得分: 14

James Antill的回答中:

foo := <-ch     // 这会阻塞。
foo, ok := <-ch // 这会立即返回。

另外,一个潜在的陷阱:接收和发送操作符之间的微妙差异

a <- ch // 将ch发送到通道a
<-ch    // 从通道ch读取
英文:

From James Antill's answer:

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

Also, a potential pitfall: the subtle difference between the receive and send operators:

a &lt;- ch // sends ch to channel a
&lt;-ch    // reads from channel ch

答案11

得分: 14

命名的结果参数

Go函数的返回或结果“参数”可以被赋予名称,并且可以像普通变量一样使用,就像传入的参数一样。当命名时,在函数开始时它们被初始化为它们类型的零值;如果函数执行一个没有参数的返回语句,结果参数的当前值将作为返回值使用。

名称不是强制的,但它们可以使代码更简洁和清晰:它们是文档。如果我们给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;
}
英文:

Named result parameters

> The return or result "parameters" of a
> Go function can be given names and
> used as regular variables, just like
> the incoming parameters. When named,
> they are initialized to the zero
> values for their types when the
> function begins; if the function
> executes a return statement with no
> arguments, the current values of the
> result parameters are used as the
> returned values.
>
> The names are not mandatory but they
> can make code shorter and clearer:
> they're documentation. If we name the
> results of nextInt it becomes obvious
> which returned int is which.

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

>Because named results are initialized and tied to an unadorned return, they can simplify as well as clarify. Here's a version of io.ReadFull that uses them well:

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

答案12

得分: 13

/*

  • 用任意数量的硬币可以组成多少种不同的£2?
  • 现在没有分号了!
    */

package main
import "fmt"

/* 这一行花了我超过10分钟才弄明白。

  • "[]" 表示 "自己计算大小"
  • 如果只指定 "[]",它会尝试创建一个切片,切片是对现有数组的引用。
  • 另外,":=" 在这里不起作用。
    */
    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 }

// 递归按预期工作
return howmany(amount, max-1) + howmany(amount-coin[max], max)

}

func main() {
fmt.Println(howmany(200, len(coin)-1))
}

英文:
/* 
 * How many different ways can &#163;2 be made using any number of coins?
 * Now with 100% less semicolons!
 */

package main
import &quot;fmt&quot;


/* This line took me over 10 minutes to figure out.
 *  &quot;[...]&quot; means &quot;figure out the size yourself&quot;
 * If you only specify &quot;[]&quot;, it will try to create a slice, which is a reference to an existing array.
 * Also, &quot;:=&quot; doesn&#39;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 &lt; 0 { return 0 }
    if max &lt;= 0 &amp;&amp; amount &gt;= 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))
}

答案13

得分: 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()方法。

英文:

I like that you can redefine types, including primitives like int, as many times as you like and attach different methods. Like defining a RomanNumeral type:

package main

import (
	&quot;fmt&quot;
	&quot;strings&quot;
)

var numText = &quot;zero one two three four five six seven eight nine ten&quot;
var numRoman = &quot;- I II III IV V VI VII IX X&quot;
var aText = strings.Split(numText, &quot; &quot;)
var aRoman = strings.Split(numRoman, &quot; &quot;)

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(&quot;Number: &quot;, i, TextNumber(i), RomanNumber(i))
}

Which prints out

Number:  5 five V

The RomanNumber() call is essentially a cast, it redefines the int type as a more specific type of int. And Println() calls String() behind the scenes.

答案14

得分: 12

<h2>返回一个通道</h2>
这是一个非常重要的真正的习语:如何将数据输入通道并在之后关闭它。通过这个,你可以创建简单的迭代器(因为范围将接受一个通道)或过滤器。

// 返回一个通道,该通道将输入通道中的值加倍
func DoublingIterator(input chan int) chan int {
    outch := make(chan int);
    // 启动一个goroutine来异步地填充通道
    go func() {
        for x := range input {
            outch &lt;- 2*x;    
        }
        // 关闭我们创建和控制的通道
        close(outch);
    }();
    return outch;
}
英文:

<h2>Returning a channel</h2>
This is a true idiom that is quite important: how to feed data into a channel and close it afterwards. With this you can make simple iterators (since range will accept a channel) or filters.

// 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 &lt;- 2*x;    
        }
        // close the channel we created and control
        close(outch);
    }();
    return outch;
}

答案15

得分: 11

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

由于range自动检查关闭的通道,我们可以简化为:

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

英文:
for {
	v := &lt;-ch
	if closed(ch) {
		break
	}
	fmt.Println(v)
}

Since range automatically checks for a closed channel, we can shorten to this:

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

答案16

得分: 11

通道读取的超时:

ticker := time.NewTicker(ns);
select {
    case v := <- chan_target:
        处理_v;
    case <- ticker.C:
        处理超时;
}

Davies Liu中借鉴。

英文:

Timeout for channel reads:

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

Stolen from Davies Liu.

答案17

得分: 9

在$GOROOT/src中设置了一个可以使用的构建系统。

使用以下内容设置您的makefile:

TARG=foobar           # 要编译的包的名称
GOFILES=foo.go bar.go # Go源文件
CGOFILES=bang.cgo     # 需要运行cgo的源文件
OFILES=a_c_file.$O    # 使用$Oc编译的源文件
                      # $O是架构编号(x86_64为6)

include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg

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

英文:

There is a make system set up that you can use in $GOROOT/src

Set up your makefile with

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

You can then use the automated testing tools by running make test, or add the package and shared objects from cgo to your $GOROOT with make install.

答案18

得分: 7

这是一个栈的实现。它演示了如何在类型上添加方法。

我想将栈部分改成切片并使用切片的属性,但是尽管我在没有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()
}
英文:

This is an implementation of a stack. It illustrates adding methods onto a type.

I wanted to make the stack part of it into a slice and use the slice's properties, but although I got that to work without the type, I couldn't see the syntax for defining a slice with a type.

package main

import &quot;fmt&quot;
import &quot;os&quot;

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 &gt;= stack_max-1 {
		fmt.Print(&quot;Oh noes\n&quot;)
		os.Exit(1)
	}
	s.size++
	s.stack[n] = pushed_string
}

func (s *Stack2) pop() string {
	n := s.size
	if n == 0 {
		fmt.Print(&quot;Underflow\n&quot;)
		os.Exit(1)
	}
	top := s.stack[n-1]
	s.size--
	return top
}

func (s *Stack2) print_all() {
	n := s.size
	fmt.Printf(&quot;Stack size is %d\n&quot;, n)
	for i := 0; i &lt; n; i++ {
		fmt.Printf(&quot;%d:\t%s\n&quot;, i, s.stack[i])
	}
}

func main() {
	stack := new(Stack2)
	stack.print_all()
	stack.push(&quot;boo&quot;)
	stack.print_all()
	popped := stack.pop()
	fmt.Printf(&quot;Stack top is %s\n&quot;, popped)
	stack.print_all()
	stack.push(&quot;moo&quot;)
	stack.push(&quot;zoo&quot;)
	stack.print_all()
	popped2 := stack.pop()
	fmt.Printf(&quot;Stack top is %s\n&quot;, popped2)
	stack.print_all()
}

答案19

得分: 7

在Go语言中,另一个有趣的事情是godoc。你可以在电脑上将其作为一个Web服务器运行,使用以下命令:

godoc -http=:8080

其中8080是端口号,然后整个golang.org网站就可以在localhost:8080上访问了。

英文:

Another interesting thing in Go is that godoc. You can run it as a web server on your computer using

godoc -http=:8080

where 8080 is the port number, and the entire website at golang.org is then available at localhost:8080.

答案20

得分: 4

从Go调用C代码

通过使用C运行时,可以访问Go的底层。

C函数的形式为

void package·function(...)

(注意点分隔符是一个Unicode字符),其中参数可以是基本的Go类型、切片、字符串等。要返回一个值,请调用

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以获取在运行时中使用的示例。

还可以参考此答案以了解如何将C++代码与Go链接起来。

英文:

Calling c code from go

It's possible to access the lower level of go by using the c runtime.

C functions are in the form

void package&#183;function(...)

(note the dot seperator is a unicode character) where the arguments may be basic go types, slices, strings etc. To return a value
call

FLUSH(&amp;ret)

(you can return more than one value)

For instance, to create a function

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

in C you use

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

Note that you still should declare the function in a go file, and that you'll have to take care of memory yourself. I'm not sure if it's possible to call external libraries using this, it may be better to use cgo.

Look at $GOROOT/src/pkg/runtime for examples used in the runtime.

See also this answer for linking c++ code with go.

答案21

得分: 4

这是一个使用sqlite3包的Go示例。

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

英文:

Here is a go example using the sqlite3 package.

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

答案22

得分: 3

const ever = true

for ever {
// 无限循环
}

英文:
const ever = true

for ever {
    // infinite loop
}

答案23

得分: 3

基于其他答案的堆栈,但使用切片添加来避免大小限制。

package main

import "fmt"
import "os"

type Stack2 struct {
        // 堆栈的初始存储空间
        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("下溢\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("堆栈大小为 %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)
        // 将切片初始化为空切片
        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("堆栈顶部为 %s\n", popped)
        stack.print_all()
        stack.push("moo")
        stack.push("zoo")
        stack.print_all()
        popped2 := stack.pop()
        fmt.Printf("堆栈顶部为 %s\n", popped2)
        stack.print_all()
}
英文:

A stack based on the other answer, but using slice appending to have no size limit.

package main

import &quot;fmt&quot;
import &quot;os&quot;

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(&quot;Underflow\n&quot;)
                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(&quot;Stack size is %d\n&quot;, len(s.cur))
        for i, s := range s.cur {
                fmt.Printf(&quot;%d:\t%s\n&quot;, 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(&quot;boo&quot;)
        stack.print_all()
        popped := stack.pop()
        fmt.Printf(&quot;Stack top is %s\n&quot;, popped)
        stack.print_all()
        stack.push(&quot;moo&quot;)
        stack.push(&quot;zoo&quot;)
        stack.print_all()
        popped2 := stack.pop()
        fmt.Printf(&quot;Stack top is %s\n&quot;, popped2)
        stack.print_all()
}

答案24

得分: 2

在主目录的test文件夹中有很多小程序。例如:

  • peano.go 打印阶乘。
  • hilbert.go 包含一些矩阵乘法。
  • iota.go 包含奇怪的 iota 用法的示例。
英文:

There are a lot of small programs in test in the main directory. Examples:

  • peano.go prints factorials.
  • hilbert.go has some matrix multiplication.
  • iota.go has examples of the weird iota thing.

huangapple
  • 本文由 发表于 2009年11月12日 13:58:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/1720201.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定