我要用cgo + stringer来制作今年(2015年)流行的“进捗· どう·です·か”表情

2015年,在工程师圈中,什么事情让人们谈论纷纷呢?
对我来说,我记得最深的就是”进度如何”这个话题。
它在许多不同的编程语言中都得到了实现。

(Golang的进展如何?)它已经存在了,我自己比较晚才上车,所以一直作为旁观者观察着。但因为它是今年的代表话题,而今年也是最后一次,所以我也决定加入其中,尝试着在cgo上进行。

境外组织

从根本上说,它是用于在Golang和C语言之间相互使用函数的包。

package main

/*
#include <stdio.h>
void hello_world() {
    printf("%s\n", "Hello World!!");
}
*/
import "C"

func main() {
    C.hello_world()
}

以上的代码是从Golang到C语言的单向传输关系。
起初,我有点冲动地想以这种方式构建,不过之后我醒悟过来说:“这不就是C语言的圣诞日历吗!”于是我恢复了理智,并决定尝试结合之前从未使用过的stringer工具。

投送者

简单来说,这是一个可以获取使用golang常量(使用iota的)的常量名称的命令。
这个命令也可以在“golang的进展如何”这个问题中使用。

package main

import (
    "fmt"
)

type マキシマムザホルモン int

const (
    マキシマムザ亮君 マキシマムザホルモン = iota
    上ちゃん
    ダイスケはん
    ナヲ
)

func main() {
    var mth マキシマムザホルモン = ダイスケはん
    fmt.Println(mth)
}

如果按照现在这样的话,只会显示为2。
我真的很想要显示为”ダイスケはん”!
就在那个时候,使用stringer。

$ go get -u -v golang.org/x/tools/cmd/stringer
$ stringer -type マキシマムザホルモン main.go

当您输入以上命令时,将生成以下类型的.go文件。

// Code generated by "stringer -type マキシマムザホルモン main.go"; DO NOT EDIT

package main

import "fmt"

const _マキシマムザホルモン_name = "マキシマムザ亮君上ちゃんダイスケはんナヲ"

var _マキシマムザホルモン_index = [...]uint8{0, 24, 36, 54, 60}

func (i マキシマムザホルモン) String() string {
    if i < 0 || i >= マキシマムザホルモン(len(_マキシマムザホルモン_index)-1) {
        return fmt.Sprintf("マキシマムザホルモン(%d)", i)
    }
    return _マキシマムザホルモン_name[_マキシマムザホルモン_index[i]:_マキシマムザホルモン_index[i+1]]
}

如果你这样操作,那么大助先生就会出现。

$ go run *.go 
ダイスケはん

顺便说一句,文件名也可以在命令执行时通过-output选项指定,所以当类型名为日语时,强烈建议指定w

$ stringer -type マキシマムザホルモン -output mth_string.go main.go

制作

只是调用用C语言编写的程序感觉有点无聊,所以我把它们改成了相互调用的程序。

package wap

/*
extern void wap(void);
*/
import "C"
import "fmt"

type word int

const (
    進捗 word = iota
    どう
    です
    
)

//export printWord
func printWord(num C.int) C.int {
    fmt.Print(word(num))

    return num
}

// Wap is "what about progress?"
func Wap() {
    C.wap()
}

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "_cgo_export.h"

void wap(void) {
  srand(time(NULL));
  int w = 0, n = 0;

  for (;;) {
    n++;

    int s = printWord(rand() % 4);

    if (w != s) {
      if (s == 0) {
        w = 1;
      } else {
        w = 0;
      }
    } else {
      w++;
      if (w == 4) {
        break;
      }
    }
  }

  printf("%s",
         "\n"
         "_人人人人人人人_\n"
         ">進捗どうですか<\n"
         " ̄Y^Y^Y^Y^Y^Y^Y ̄\n");
  printf("%d回で煽られました\n", n);
}

在Golang中调用的C语言函数是`wap(void)`,而在C语言中调用的Golang函数是`printWord(num C.int)`。
通过使用stringer效果并编写`fmt.Print(word(num))`,只需这样一行代码,就可以实现显示”進捗”、”どう”、”です”或”か”中的任何一个。

最初我是在main包里面进行编程,但是遇到了以下错误而无法运行,让我感到非常困扰。

# command-line-arguments
Undefined symbols for architecture x86_64:
  "_wap", referenced from:
      __cgo_57c8a91b469e_Cfunc_wap in wap.cgo2.o
     (maybe you meant: __cgo_57c8a91b469e_Cfunc_wap)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

回: [go-nuts] Cgo和libccv: “未定义的符号”
阅读这些的时候,好像有一个标志能够工作,但总之,我通过阅读cgo · golang/go Wiki并将其实施为与main不同的包的方法来解决了这个问题。
我认为因为已经变成了一个包,所以任何人都可以使用它了。(谁会用呢!)

可以

github.com/178inaba/wap的汉语翻译选项:

如果您想尝试,请在example目录中运行go run main.go,并告诉我进展情况。

$ go get -u github.com/178inaba/wap
$ cd $GOPATH/src/github.com/178inaba/wap/example
$ go run main.go
進捗進捗どう進捗ですか進捗進捗ですかですです進捗ですですです進捗かですかか進捗か進捗どうですどう進捗進捗進捗ですどうどうどうどうどう進捗どうか進捗どうかです進捗ですですですかかかです進捗どうです進捗かかかどう進捗進捗どうどうか進捗ですか進捗かかか進捗どうかですですか進捗どう進捗どうどう進捗進捗どうですか
_人人人人人人人_
>進捗どうですか<
 ̄Y^Y^Y^Y^Y^Y^Y ̄
87回で煽られました

由于已经打包,因此example的main.go文件只是调用了wap.Wap()。

package main

import "github.com/178inaba/wap"

func main() {
    wap.Wap()
}

只要在你的程序中写上 wap.Wap(),我就可以查看进度了。你觉得要不要用命令行工具呢?哈哈哈。

顺便提一下,“wap”是“What about progress? (進捗如何?)”的缩写。

最后

大家好,2015年的进展如何?

广告
将在 10 秒后关闭
bannerAds