Golang使用swig包装C/C++程序为Go包 For Windows

swig不能直接使用官方的程序,而必须打一个patch 后才能使用。svn下载swig源代码后(看版本号应该是2.0.5了),打上
swig_go_windows2.patch
这个patch。至于怎么打patch,请自行Google之。

swig的编译也是比较折腾的。因为他依赖 yodl2man yodl2html这东西,而这东西又依赖 icmake,不过后来发现这东西不要也行,虽然 swig在 make install的时候没有完全结束,但是生成的东西,已经够用了。

把C写的库包装为 GO包。

首先需要准备两个文件 test.i test.c

$ cat test.c
#include 
double MyVar = 3.0;

int Fact(int n) {
    if (n <= 1) return 1;
    else return n * Fact(n-1);
}

int MyMod(int x, int y) {
    return (x % y);
}

char *GetTime() {
    time_t ltime;
    time(&ltime);
    return ctime(&ltime);
}

$ cat test.i
%module test
%{
    extern double MyVar;
    extern int Fact(int n);
    extern int MyMod(int x, int y);
    extern char *GetTime();
%}

extern double MyVar;
extern int Fact(int n);
extern int MyMod(int x, int y);
extern char *GetTime();

需要注意的是 C中的如果要想在Go中可以调用 ,首字母必须要 大写。开始 swig

//初始
$ ls
test.i test.c
//使用swig生成需要的文件
$ swig -go -windows test.i
$ ls
test.c  test.go  test.i  test_dllmain.cxx  test_gc.c  test_wrap.c
//分别编译 test.c test_wrap.c test_dllmain.cxx 为目标文件 *.o
$ gcc -c test.c test_wrap.c test_dllmain.cxx
//将上一步编译的结果链接成一个动态链接库
$ gcc -shared test.o test_wrap.o test_dllmain.o -o test.dll
//编译 test.go
$ 8g test.go
//编译 test_gc.c
$ 8c -I "go的pkg目录" test_gc.c
//将test.8 test_gc.8 打包成go库,就是一个静态库,相当于gcc里面使用 ar 命令打包一样。
$ gopack grc test.a test.8 test_gc.8

至此万事俱备了。写个go 程序来试试。

$ cat main.go
package main

import "./test"
import "fmt"

func main() {
    println(test.Fact(5))
    //println(test.MyVar)   //不能直接调用必须使用 getter setter来调用如下
    test.SetMyVar(99)      //来设置 MyVar的值
    fmt.Printf("%f
", test.GetMyVar())   //取得刚设置的值。
    println(test.MyMod(10, 3))
    println(test.GetTime())
}

$ 8g main.go
$ 8l main.8
$ ./8.out.exe
120
1
Thu Jun 23 04:06:40 2011

现在把 test.dll改名,看看这个程序是不是真调用 了这个动态链接库。

如果要在其它地方使用只需要 test.a 及 test.dll 两个文件 。。test.a就是go的库,这是魔法所在,就是这样东西负责调用 C里面的函数。。因为Go是静态编译,所以编译好的Go程序就不需要 test.a这东西了,只要test.dll带上就行了。。

编译好的Go-GTK包及相关gtk依赖 for Windows

go-gtk.png

到gtk官方下载 打包好的 windows gtk bundle all-in-one包。解压后 把在本站下载的 gtk+-bundle_2.22.1.7z 解压覆盖到里面,其实只是解决 gtksourceview及libxml2的依赖。

把 go-gtk.7z 解压放到你的 go pkg库目录下。

注:本人使用的是 mingw环境。
8g version weekly.2011-06-16 8787
go-gtk 最新git下载的 revision:1193a0044982261ccf04805ff36e11002d368ad7

go-gtk.7z

gtk+-bundle_2.22.1.7z

更新go 8g version release.r59 9087编译的版本:go-gtk-r59.tar.xz

Golang Go语言 container/ring闭环数据结构的使用方法

//引入包
import "container/ring"
//创建闭环,这里创建10个元素的闭环
r := ring.New(10)
//给闭环中的元素附值
for i := 1; i <= r.Len(); i++ {
    r.Value = i
    r = r.Next()
}
//循环打印闭环元素的值,这里的操作方法很像javascript
r.Do(func(p interface{}){
    println(p)
})
//当前元素就是
// r
//当前元素的值就是
// r.Value       //这里是 1
//取得当前元素之后的第5个元素
r5 := r.Move(5)    //这里是 6
//链接 当前元素r与r5,相当于删除了r跟r5之间的元素,使 r.Next() == r5
rl := r.Link(r5)  //这样 r环里有 1 6 7 8 9 10
                    //rl 环路里有  2 3 4 5 

//把rl环加回到 r环原来的位置
//要确保r的当前位置是 1,rl的当前位置为2
rf := r.Link(rl)
//这样 r就变回了 1 2 3 4 5 6 7 8 9 10
//rf则是 从 rl.Next()开始环,内容则与 r的一样。
//6 7 8 9 10 1 2 3 4 5
另外做过一次 Do()循环操作后 闭环的当前位置不变。

Golang Go语言插入排序

package main 

//插入排序
func main() {
    a := []int{5, 4, 3, 2, 1}
    for i := 1; i < len(a); i++ {
        temp := a[i]
        j := i - 1
        for j >= 0 && a[j] > temp {
            a[j + 1] = a[j]
            j--
        }
        a[j + 1] = temp
    }
    for _, v := range a {
        println(v)
    }
}

原理就是依顺找到每个元素在己排充部分中自己的位置,并插入。

Golang Go语言希尔排序

package main  

//希尔排序
func main() {
    a := []int{5, 4, 3, 2, 1}
    gap := 0
    for gap * 3 + 1 < len(a) {
    gap = gap * 3 + 1
    }
    for gap > 0 {  //分段 

        for i := gap; i < len(a); i++ {   //对分段进行插入排序
            temp := a[i]
            j := i - gap
            for j >= 0 && a[j] > temp {
                a[j + gap] = a[j]
                j -= gap
            }
            a[j + gap] = temp
        }
        gap = (gap - 1) / 3 

    }
    for _, v := range a {
        println(v)
    }
}

希尔排序就是分段了的插入排序。最大限度地提高每次对比后元素移动的距离。gap = gap * 3 + 1分隔数由实验取得。如 1 4 13之类。反顺减小到 1。

Golang Go语言限制goroutine数量的方法

package main 

import "time" 

func work(ch chan int) {  //工作方法
    //做事
    <- ch  //完事后在 ch里面抽一个数。
} 

func main() {
    ch := make(chan int, 100)  //限制100个goroutine
    for i := 0; ; i++ {
        ch <- 1              //如果当有已经有100个goroutine在工作,那么此事就会堵塞直到有goroutine工作完
        go work(ch)
    }
}

Golang Go语言发送邮件的方法

传统的思路

package main

import (
        "log"
        "smtp"
)

func main() {
        // Set up authentication information.
        auth := smtp.PlainAuth(
                "",
                "user@example.com",
                "password",
                "mail.example.com",
        )
        // Connect to the server, authenticate, set the sender and recipient,
        // and send the email all in one step.
        err := smtp.SendMail(
                "mail.example.com:25",
                auth,
                "sender@example.org",
                []string{"recipient@example.net"},
                []byte("This is the email body."),
        )
        if err != nil {
                log.Fatal(err)
        }
}

Go语言流式操作方法来发邮件

package main

import (
        "log"
        "smtp"
)

func main() {
        // Set up authentication information.
        auth := smtp.PlainAuth(
                "",
                "user@example.com",
                "password",
                "mail.example.com",
        )
        // Connect to the remote SMTP server.
        c, err := smtp.Dial("mail.example.com:25")
        if err != nil {
                log.Fatal(err)
        }
        err = c.Auth(auth)
        if err != nil {
        	log.Fatal(err)
        }
        // Set the sender and recipient.
        c.Mail("sender@example.org")
        c.Rcpt("recipient@example.net")
        // Send the email body.
        wc, err := c.Data()
        if err != nil {
                log.Fatal(err)
        }
        defer wc.Close()
        if _, err = wc.Write([]byte("This is the email body.")); err != nil {
                log.Fatal(err)
        }
}


英文来源
,做过一点点修改。

给网站添加Google+1按钮的方法

网站为何要添加一个新的按钮?

按钮多了,可能有的人会觉得烦了,那么Google+1加了有何用呢?目前情况是:更多人给你的网站+1,那么就有更多的可能,更多的人搜索的时候在Google搜索结果里面显示他们社交圈朋友的推荐内容,而你的网站就是被推荐的条目。

怎么给网站添加Google+1按钮?

在网页 head 区放置这段js代码


然后在要放Google+1按钮的地方放入如下代码:


默认情况下使用的按钮大小是 24px的。而且被推荐的网址是当前网页地址。如果要改变这两个东西需要设置参数。

Google+1按钮参数说明

按钮大小包括四种:small 15px大小 medium 20px大小 standard 24px大小 tall 60px大小。
比如要设置为 20px大小的 medium。则代码为


推荐的网址:写在 href参数里面,比如要推荐的网址为 http://kejibo.com则代码为


设置是否显示已经被推荐的次数:参数为 count,如果显示(默认情况):属性为 true,如果不想显示就设置为 false如


Golang Go语言结构体中匿名字段暴露方法的优先级

Go语言的结构体中可以包含匿名的字段,比如:

struct {
	T1        // 字段名自动为 T1
	*T2       // 字段名自动为 T2
	P.T3      // 字段名自动为 T3
	*P.T4     // 字段名自动为 T4
	x, y int  // 非匿名字段 x , y
}

如果结构体 S,包含一个匿名字段 T,那么这个结构体 S 就有了 T的方法。
如果包含的匿名字段为 *T,那么这个结构体 S 就有了 *T 的方法。
如果S包含的匿名字段为 T或*T,那么 *S就有了 *T的方法。

比如

type gzipResponseWriter struct {
    io.Writer
}

因为 io.Writer里有 Write方法,所以 gzipResponseWriter 也有了 Write方法

var g gzipResponseWriter
g.Write(数据)

此处的 g.Write 就相当于 g.Writer.Write(数据)。

那么如果两个匿名字段都有同一个方法的时候,会怎么样呢?

type gzipResponseWriter struct {
    io.Writer
    http.ResponseWriter
}

io.Writer这个接口已经有 Write方法了,http.ResponseWriter 同样有 Write方法。那么对 g.Write写的时候,到底调用哪个呢?是 g.Writer.Write 还是 g.ResponseWriter.Write呢?你不知道程序也不知道,如果编译就出现“Write模糊不清”的错误。

怎么解决这个问题?

其一:就是重写 gzipResponseWriter的 Write方法,指明要写到哪一方。

func (w gzipResponseWriter) Write(b []byte) (int, os.Error) {
    return w.Writer.Write(b)
}

上面这里就是指定使用 io.Writer里面的 Write方法。

其二:使用匿名字段暴露方法优先级来确定重复方法的时候使用哪一个方法,原则就是【简单优先】。所以我们这里把 http.ResponseWriter弄复杂一点,使用另一个结构体先包裹一次。

type responseWriter struct {
    http.ResponseWriter
}

然后再在 gzipResponseWriter里面插入这个结构体

type gzipResponseWriter struct {
	io.Writer
	responseWriter
}

这样就是 io.Writer的方法是会优先暴露出来的。这样就省去了上面那样的麻烦,而且当有多个重复方法的时候,还得一个一个来改写。记得使用 gzipResponseWriter 的时候原来的 类型为 http.ResponseWriter 的对象比如 w,要用 responseWriter{w},包装一下就可以使用到 gzipResponseWriter里面了。


参考英文及评论内容

Golang Go语言中的try … except …统一的异常处理

写python的时候,有时候懒得一个一个错误去分别处理,直接使用一个整体来try catch来捕获所有异常。如:

try:
	one()
	two()
	three()
except:
	处理异常

Go中的实现方式:

func main() {
        defer func() {
        	if e, ok := recover(); ok {
			println(e.String())  //打印出错误
		}
        }()
        one()
        two()
        three()
        ...
}

这样one two three任何一个执行中的异常都会被前面的这个闭包函数捕获。