<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Some reminiscences, some memories</title>
	<atom:link href="http://www.mikespook.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mikespook.com</link>
	<description>Just another boring day</description>
	<lastBuildDate>Mon, 07 May 2012 00:57:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>MyMySQL 的 database/sql 接口使用</title>
		<link>http://www.mikespook.com/2012/05/mymysql-%e7%9a%84-databasesql-%e6%8e%a5%e5%8f%a3%e4%bd%bf%e7%94%a8/</link>
		<comments>http://www.mikespook.com/2012/05/mymysql-%e7%9a%84-databasesql-%e6%8e%a5%e5%8f%a3%e4%bd%bf%e7%94%a8/#comments</comments>
		<pubDate>Fri, 04 May 2012 08:37:52 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1277</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
最近看到不少朋友对 Golang 中操作 MySQL 数据库有疑问，那么就此内容给大家分享一下吧。

MyMySQL 的原作者是来自波兰的 ziutek，他根据 MySQL 的协议标准使用 Golang 实现了 MyMySQL 包。根据他的介绍，这个包可以用在 MySQL 4.1 或更高版本上，并且在 5.0、5.1 版本上经过项目的实际验证。

只要用 MySQL 做过项目的朋友一定遇到过编码问题，set names 几乎成为了中文环境下使用 MySQL 的标配。那么 Golang 也不能例外。不过由于 database/sql 使用了随机的连接池，且未提供任何方法让所有连接都执行某个操作，于是这个麻烦事儿就落到了驱动的肩上。对于中文什么的，大老外一向不怎么在意。我提交了这个 issue 给 ziutek，不过对于他最终实现的方案不怎么满意。需要额外编写godrv.Register 来对编码进行设置。

<span class="readmore"><a href="http://www.mikespook.com/2012/05/mymysql-%e7%9a%84-databasesql-%e6%8e%a5%e5%8f%a3%e4%bd%bf%e7%94%a8/" title="MyMySQL 的 database/sql 接口使用">阅读全文——共3136字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>最近看到不少朋友对 Golang 中操作 MySQL 数据库有疑问，那么就此内容给大家分享一下吧。</p>
<p>MyMySQL 的原作者是来自波兰的 <a href="https://github.com/ziutek/" title="ziutek" target="_blank">ziutek</a>，他根据 MySQL 的协议标准使用 Golang 实现了 <a href="https://github.com/ziutek/mymysql" target="_blank">MyMySQL</a> 包。根据他的介绍，这个包可以用在 MySQL 4.1 或更高版本上，并且在 5.0、5.1 版本上经过项目的实际验证。</p>
<p>只要用 MySQL 做过项目的朋友一定遇到过编码问题，set names 几乎成为了中文环境下使用 MySQL 的标配。那么 Golang 也不能例外。不过由于 database/sql 使用了随机的连接池，且未提供任何方法让所有连接都执行某个操作，于是这个<a href="http://codereview.appspot.com/5706047/" target="_blank">麻烦事儿就落到了驱动的肩上</a>。对于中文什么的，大老外一向不怎么在意。我提交了这个 issue 给 ziutek，不过对于他最终实现的方案不怎么满意。需要额外编写godrv.Register 来对编码进行设置。</p>
<p>同时当连接空闲时间超出服务器的 wait_timeout 时，会出现 broken pipe。对于这个问题，ziutek 的建议是使用 MyMySQL 的 autorc，但是 godrv 并没有基于 autorc 实现 database/sql。换句话说，要解决这个错误，只能使用 MyMySQL 原始接口。</p>
<p>鉴于这些问题，我只能 fork 了 ziutek 的项目，对 <a href="https://github.com/mikespook/mymysql" target="_blank">MyMySQL</a> 打上相应的补丁。主要是针对编码设置进行了改进，并顺便实现了 keepalive 功能。</p>
<p>本文主要介绍 fork 的版本的使用。<br />
<span id="more-1277"></span></p>
<p>在 fork 的版本中，还有一个改进就是统一了 go get 的安装接口，无需再逐一安装 MyMySQl 的子包，只需要</p>
<pre class="brush: bash; title: ; notranslate">
go get github.com/mikespook/mymysql
</pre>
<p>即可完成安装。</p>
<p>关于使用，还是用代码说话吧，完整代码看<a href="http://play.golang.org/p/kMchqTg93a" target="_blank">这里</a>。为了通用，这里只介绍使用 <a href="http://golang.org/pkg/database/sql/" target="_blank">database/sql</a> 接口的使用。在实际项目中，我也建议大家尽量使用该接口，这样在最大可用性保障下保持兼容性。</p>
<pre class="brush: java; title: ; notranslate">
import(
    &quot;log&quot;
    &quot;database/sql&quot;
    _ &quot;github.com/mikespook/mymysql/godrv&quot;
)
</pre>
<p>使用 MyMySQL 的 database/sql 接口要导入 godrv 包。在这个包的 init 函数中自动注册了 database/sql 的驱动，所以导入后无需再使用。</p>
<pre class="brush: java; title: ; notranslate">
db, err := sql.Open(&quot;mymysql&quot;, &quot;tcp://127.0.0.1:3306/test/root/xxiyy?charset=utf8&amp;keepalive=1200&quot;)
if err != nil {
    log.Fatal(err)
}
defer db.Close()
</pre>
<p>使用 mymysql 驱动打开一个 sql.DB 连接。dsn 连接串是我对 ziutek 的 MyMySQL 的主要改进。支持多种连接方式：</p>
<ul>
<li>使用 tcp 协议：[tcp://addr/]dbname/user/password[?params]</li>
<li>使用 unix sock：[unix://sockpath/]dbname/user/password[?params]</li>
</ul>
<p>其中 tcp 协议的 addr 必须是含有主机名或 ip，且包含又分号分隔的端口号的字符串。如 localhost:3306、192.168.3.2:3307。unix sock 协议中的 sockpath 必须是 MySQL 的 sock 文件的绝对路径。</p>
<p>在上述 dsn 中，方括号内的是可选的内容，可省略。当协议信息（第一个方括号内）未指定时，使用 tcp://127.0.0.1:3306/ 作为默认值。 </p>
<p>params 部分是用于当前数据库驱动的参数设置，当前来说，只有两个可设置的参数：</p>
<ul>
<li>charset：用于 &#8216;set names&#8217; 设置连接编码。</li>
<li>keepalive：每 keepalive 秒向服务器发送 PING。</li>
</ul>
<p>需要特别强调的是，如果密码含有斜线（/），由于解析规则的缘故，需要用星号（*）代替。如果密码含有星号（*），则需要用两个星号（**）代替。例如：</p>
<ul>
<li>原密码 [pass/wd]，在 dsn 中应写为 [pass*wd]。</li>
<li>原密码 [pass*wd]，在 dsn 中应写为 [pass**wd]。</li>
</ul>
<pre class="brush: java; title: ; notranslate">
stmt, err := db.Prepare(&quot;insert into `test` (`key`, `value`) values (?, ?)&quot;)
if err != nil {
    log.Fatal(err)
}
defer stmt.Close()
rslt, err := stmt.Exec(&quot;name&quot;, &quot;foobar&quot;)
if err != nil {
    log.Fatal(err)
}
if a, err := rslt.RowsAffected(); err != nil {
    log.Print(err)
} else {
    log.Printf(&quot;[INS]Affected rows=%d&quot;, a)
}
if id, err := rslt.LastInsertId(); err != nil {
    log.Print(err)
} else {
    log.Printf(&quot;[INS]Last insert id=%d&quot;, id)
}
</pre>
<p>在 database/sql 接口里，有多种办法执行某个 SQL 语句。出于安全考虑，强烈建议大家不要使用字符串方式直接拼接 SQL 语句进行执行，如果可能，在大多数其他接口中都会出现的 Prepare 方法是首选。执行完 SQL 语句后，可以通过 sql.Result 得到这次执行所影响的行数，和最后插入的 Id 值。如果表中没有使用 autoincrement 作为主键，那么这个 Id 值永远为 0。</p>
<pre class="brush: java; title: ; notranslate">
rows, err := db.Query(&quot;select * from `test`&quot;)
if err != nil {
    log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
    var k, v string
    rows.Scan(&amp;k, &amp;v)
    log.Printf(&quot;[ROWS]key=%s, value=%s&quot;, k, v)
}
</pre>
<p>查询一个二维表，从中取得多行数据使用 Query 方法。需要注意的是 sql.Rows 的 Scan 方法接收的参数必须是指针。也就是说存放数据的地址要在 Scan 调用前准备好。Scan 内部使用了反射来识别参数类型并进行赋值，也可以传递一个 []interface{}。这时必须这样调用：rows.Scan(a&#8230;) 才能得到预期结果。</p>
<pre class="brush: java; title: ; notranslate">
row := db.QueryRow(&quot;select * from `test` where `key` = ?&quot;, &quot;name&quot;)
var k, v string
row.Scan(&amp;k, &amp;v)
log.Printf(&quot;[ROW]key=%s, value=%s&quot;, k, v)
</pre>
<p>对于有些如用主键进行的查询，仅仅会读出一行数据。那么可以用 QueryRow 进行更加简化的读取。</p>
<pre class="brush: java; title: ; notranslate">
rslt, err = db.Exec(&quot;delete from `test`&quot;)
if a, err := rslt.RowsAffected(); err != nil {
    log.Print(err)
} else {
    log.Printf(&quot;[DEL]Affected rows=%d&quot;, a)
}
if id, err := rslt.LastInsertId(); err != nil {
    log.Print(err)
} else {
    log.Printf(&quot;[DEL]Last insert id=%d&quot;, id)
}
</pre>
<p>对于没有拼接 SQL 需要的操作，可以直接在 sql.DB 对象上调用 Exec 方法。返回的 sql.Result 与 sql.Stmt 的 Exec 方法一致。</p>
<p>关于基础的使用，大致就这些内容。database/sql 也支持事物，这部分信息大家可以参考其<a href="http://golang.org/pkg/database/sql/#DB.Begin" target="_blank">文档</a>进行学习。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/05/mymysql-%e7%9a%84-databasesql-%e6%8e%a5%e5%8f%a3%e4%bd%bf%e7%94%a8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]Go 版本 1 发布</title>
		<link>http://www.mikespook.com/2012/03/%e7%bf%bb%e8%af%91go-%e7%89%88%e6%9c%ac-1-%e5%8f%91%e5%b8%83/</link>
		<comments>http://www.mikespook.com/2012/03/%e7%bf%bb%e8%af%91go-%e7%89%88%e6%9c%ac-1-%e5%8f%91%e5%b8%83/#comments</comments>
		<pubDate>Thu, 29 Mar 2012 02:02:26 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1267</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
原文：http://blog.golang.org/2012/03/go-version-1-is-released.html

&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-

Go 版本 1 发布

<span class="readmore"><a href="http://www.mikespook.com/2012/03/%e7%bf%bb%e8%af%91go-%e7%89%88%e6%9c%ac-1-%e5%8f%91%e5%b8%83/" title="[翻译]Go 版本 1 发布">阅读全文——共1115字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>原文：<a href="http://blog.golang.org/2012/03/go-version-1-is-released.html" target="_blank">http://blog.golang.org/2012/03/go-version-1-is-released.html</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<h1>Go 版本 1 发布</h1>
<p><a href="http://www.mikespook.com/wp-content/uploads/2012/03/gophermega.jpg"><img src="http://www.mikespook.com/wp-content/uploads/2012/03/gophermega.jpg" alt="" title="gophermega" width="170" height="130" class="alignleft size-full wp-image-1268" /></a></p>
<p>今天，在 Go 编程语言的开发上标记了一个主要的里程碑。我们宣布 Go 版本 1，或者简称为 Go 1，定义了一个语言和一系列的核心库作为基础，用于创建可信赖的产品、项目和出版物。<br />
Go 1 是 Go 的第一个发布，提供了二进制包。可用于 Linux、FreeBSD、Mac OS X 以及，令人非常兴奋的——Windows。</p>
<p><span id="more-1267"></span><br />
对于用户来说 Go 1 驾驭起来相当稳定。编写 Go 1 程序的人可以完全确信在大多数环境下，即使再过若干年，仍然无需对程序做任何修改，它还能编译和运行。类似的，编写关于 Go 1 书籍的人也可以确信他们的例子和解释不论对于今天还是未来的读者都是有帮助的。</p>
<p>向前兼容是稳定的一部分。由 Go 1 编译的代码应当（很少有特例）能够继续在这个版本的生命周期内编译和运行，如为了 issue 更新和 bug 修复而产生的 Go 版本 1.1、1.2 等等。, <a href="http://golang.org/doc/go1compat.html" target="_blank">Go 1 兼容性文档</a>用更多的细节对兼容性指引进行了解释。</p>
<p>Go 1 是 Go 当前应用的一个代表，而不是重大的重构。在计划中，我们聚焦于清理问题和矛盾，并改进可移植性。在最初我们设计并制作出 Go 的原型已经过了很久，发生了很多变化，没有发布的原因是它们不能向后兼容。Go 1 包含了这些对语言和库提供了重大改进，但不能兼容旧程序的变化。幸运的是， <a href="http://golang.org/cmd/go/#Run_go_tool_fix_on_packages" target="_blank">go fix</a> 工具可以自动完成许多将程序升级到 Go 1 标准的工作。</p>
<p>Go 1 带来了语言（例如 <a href="http://golang.org/doc/go1.html#rune" target="_blank">Unicode 字符</a>和新的 <a href="http://golang.org/doc/go1.html#errors" target="_blank">errors</a> 类型）和标准库（例如新的 <a href="http://golang.org/doc/go1.html#time" target="_blank">time 包</a>和 <a href="http://golang.org/doc/go1.html#strconv" target="_blank">strconv 包</a>的重命名）的变化。同时，包的层次被总新梳理，使得相关的项目放在一起，例如调整了网络相关的<a href="http://golang.org/pkg/net/rpc/" target="_blank"> rpc 包</a>到 net 的子目录中。在 <a href="http://golang.org/doc/go1.html" target="_blank">Go 1 发布笔记</a>中有完整的变化列表。这份文档对于从 Go 早期版本迁移是必不可少的指引。</p>
<p>我们同时重构了 Go 工具包，用新的 <a href="http://golang.org/doc/go1.html#cmd_go" target="_blank">go 命令</a>作为封装，用于获取、构建、安装和管理 Go 代码。go 命令消除了编写 Go 代码时对 Makefile 的需求，因为它使用 Go 程序的代码本身驱动构建。不再需要构建脚本！</p>
<p>最终，Go 1 的发布使得 <a href="https://developers.google.com/appengine/docs/go" target="_blank">Google App Engine SDK</a> 也进行了新版本发布。类似的修订和稳定过程已经应用在 App Engine 包上，为开发者提供了在 App Engine 上构建可以运行许多年的程序的基石。</p>
<p>Go 1 是 Go 核心组和来自开源社区的贡献者共同努力的结果。我们为此向每个给予过帮助的人表示感谢。</p>
<p>没有什么时候是比现在更加适合变成一位 Go 程序员了。迈出第一步所需的一切都在 <a href="http://golang.org/" target="_blank">golang.org</a>。</p>
<p>ANDREW GERRAND 发表</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/03/%e7%bf%bb%e8%af%91go-%e7%89%88%e6%9c%ac-1-%e5%8f%91%e5%b8%83/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>73字小诗</title>
		<link>http://www.mikespook.com/2012/03/73%e5%ad%97%e5%b0%8f%e8%af%97/</link>
		<comments>http://www.mikespook.com/2012/03/73%e5%ad%97%e5%b0%8f%e8%af%97/#comments</comments>
		<pubDate>Wed, 14 Mar 2012 03:20:49 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[My life]]></category>
		<category><![CDATA[扯淡]]></category>
		<category><![CDATA[诗]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1260</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
图片来自我的另一篇博文：《围墙》——钱终输

我走了

无声无息

<span class="readmore"><a href="http://www.mikespook.com/2012/03/73%e5%ad%97%e5%b0%8f%e8%af%97/" title="73字小诗">阅读全文——共170字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<div id="attachment_343" class="wp-caption alignleft" style="width: 309px"><a href="http://www.mikespook.com/2009/06/%e3%80%8a%e5%9b%b4%e5%a2%99%e3%80%8b%e2%80%94%e2%80%94%e9%92%b1%e7%bb%88%e8%be%93/" target="_blank"><img class="size-full wp-image-343" title="The wall" src="http://www.mikespook.com/wp-content/uploads/2009/06/wall.jpg" alt="" width="299" height="400" /></a><p class="wp-caption-text">图片来自我的另一篇博文：《围墙》——钱终输</p></div>
<p>我走了<br />
无声无息<br />
来不及挥一挥手<br />
留下一声叹息</p>
<p>他日<br />
如若你看到我的骨灰<br />
请把它<br />
撒在那广场的泥潭里</p>
<p>所有人<br />
都会走得<br />
无声无息<br />
只是还有谁记得<br />
那一百六十对<br />
代表自由的翼</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/03/73%e5%ad%97%e5%b0%8f%e8%af%97/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>G+ for Android! I&#8217;m very angry with you!</title>
		<link>http://www.mikespook.com/2012/03/g-for-android-im-very-angry-with-you/</link>
		<comments>http://www.mikespook.com/2012/03/g-for-android-im-very-angry-with-you/#comments</comments>
		<pubDate>Thu, 08 Mar 2012 04:37:28 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[My life]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[shit]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1249</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
Original version from http://the-wounding-pen.blogspot.com/2011/01/why-i-write-by-george-orwell.html, thx!

Hey, guys. I don&#8217;t know how do you think about with the G+&#8217; app on the Android platform. Because I was a bored fool. I installed the G+ app into my mobile phone and got hurt from it&#8230;

<span class="readmore"><a href="http://www.mikespook.com/2012/03/g-for-android-im-very-angry-with-you/" title="G+ for Android! I&#8217;m very angry with you!">阅读全文——共3173字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<div id="attachment_1250" class="wp-caption alignleft" style="width: 360px"><a href="http://www.mikespook.com/wp-content/uploads/2012/03/Big-Brother.jpg"><img class="size-full wp-image-1250 " title="Big-Brother" src="http://www.mikespook.com/wp-content/uploads/2012/03/Big-Brother.jpg" alt="" width="350" height="503" /></a><p class="wp-caption-text">Original version from http://the-wounding-pen.blogspot.com/2011/01/why-i-write-by-george-orwell.html, thx!</p></div>
<p>Hey, guys. I don&#8217;t know how do you think about with the G+&#8217; app on the Android platform. Because I was a bored fool. I installed the G+ app into my mobile phone and got hurt from it&#8230;</p>
<p>Sorry for my bad English. I&#8217;m not good at English writing. I hope you will understand me.</p>
<p>Here&#8217;s my story, bla bla bla &#8230;</p>
<p><span id="more-1249"></span></p>
<p>As you know, in China, lots of websites were blocked by the GFW. This websites are including twitter, facebook or someother famous SNS websites. But G+ could be visited sometimes. Lucky!</p>
<p>I&#8217;m a programmer that interested in golang. Yeah, of course, Google&#8217;s golang. Most of Go-Authors are using G+. I added them to my circle. It&#8217;s cool, isn&#8217;t it? I can get a lot of information about golang form Go-Authors and the others who is also interested in golang.</p>
<p>So I installed the G+ in my Android mobile phone (Yeah, Google&#8217;s Android again. But I was never say that I&#8217;m a Google fan or in Chinese “谷粉”, isn&#8217;t it?).</p>
<p>The nightmare stated from here&#8230;</p>
<p>When I installed the G+, it ask me “1. Wifi 2. Wifi+3G 3. Never(or something else&#8230;I can remember)”. I selected Wifi+3G without thinking twice. My mobile pay package has 300 MB every month for free. It never run out, not mention run over. I <strong>DO NOT</strong> understand this three options what is at that time. And there is no more explanation or warning for me.</p>
<p>The 1st day passed, nothing happened. The next day, 3rd day, as usual.</p>
<p>This morning, I found that my mobile was out of power. Strange! I rushed to the phone fully charged. And I found that I was already out of 300MB 3G flow. And there are 51.3 MB more I must pay for it. Fortunately, It only worth $1, not too expensive, isn&#8217;t it?</p>
<p>The <strong>WORST</strong> thing is that: G+ app searched all my mobile and ext-sdcard, got all my personal photos stored in mobile, and uploaded them onto the Internet without my permission. Then I noticed that the uploading option is selected by default, no warning, no alert, no confirm. Then the G+ app tell me that I could share this online photos to my friends, friendly. Ja! friendly this time!</p>
<p>Oh shit!</p>
<p>I <strong>DO NOT</strong> want to share this photos. I <strong>DO NOT</strong> want to upload this photos onto Internet. If I would, I would do it by myself, manually!</p>
<p>I tell you guys my story, just want to remind you, be careful to your privacy, be careful to use Google&#8217;s products. They&#8217;ve already changed the privacy licence.</p>
<p>Here are some proposals to Google:</p>
<p>I&#8217;ve already uninstalled the G+ app from my mobile. I know you guys never mind losing a customer, especially this customer are living in China.</p>
<p>But I would to say:</p>
<p>I hope you guys will respect the user. <strong>DO NOT</strong> let the personal information upload automatically.</p>
<p>Eg. As in G+ app, will you plz let the upload option unselected by default. And let the user choose which photos will be uploaded. If I want to share I would do it by myself, manually.</p>
<p>Living in <strong>China</strong>, being monitored by <strong>BIG BROTHER</strong> everyday. It&#8217;s enough for me!</p>
<p>I don&#8217;t want to be watching by you, <strong>GOOGLE</strong>!</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;- LAST BUT ONE EDIT &#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Somebody said this post is no relevance to G+ and the tech world.  I must say:</p>
<blockquote><p>
Most people will hurt themselves with careless(like me, a big fool).<br />
Why our productions do not protect user far away from those bad things?<br />
Why we only think about HOW MANY USERS, HOW MANY FEATURES, HOW MANY MONEY&#8230;<br />
But don&#8217;t care about some features would take hurt to our users.
</p></blockquote>
<p>The 300MB is not important. Most of the photos are about cats and dogs.</p>
<p>BUT <strong>How do we treat user?</strong> IS THE REALLY THING.<br />
We should think over it, again and again!</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;- LAST EDIT &#8212;&#8212;&#8212;&#8212;&#8212;-<br />
<strong>I SAID AGAIN: THIS IS MY FAULT! </strong><br />
There is no need you guys remind me again and again.</p>
<p>In a words:”蠢人很多，对别人好点，自己也聪明不到哪儿去！”</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/03/g-for-android-im-very-angry-with-you/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>[翻译]Go 环境设置</title>
		<link>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e7%8e%af%e5%a2%83%e8%ae%be%e7%bd%ae/</link>
		<comments>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e7%8e%af%e5%a2%83%e8%ae%be%e7%bd%ae/#comments</comments>
		<pubDate>Wed, 29 Feb 2012 09:52:39 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1245</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
在最近的 weekly 版本中，golang 已经将大多数操作集成到了 go 这一个工具。并且环境变量的设置也发生了变化。不过蛋疼的是，如果不理解 GOPATH 的真正用法，只会让你蛋碎一地。

最常见的错误：



<span class="readmore"><a href="http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e7%8e%af%e5%a2%83%e8%ae%be%e7%bd%ae/" title="[翻译]Go 环境设置">阅读全文——共1493字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>在最近的 weekly 版本中，golang 已经将大多数操作集成到了 go 这一个工具。并且环境变量的设置也发生了变化。不过蛋疼的是，如果不理解 GOPATH 的真正用法，只会让你蛋碎一地。</p>
<p>最常见的错误：</p>
<pre class="brush: bash; title: ; notranslate">
can't load package: .: path &quot;/pla/pla/pla&quot; not inside a GOPATH
</pre>
<p>这篇文章，简短、清晰的解释了新的 go 环境应当如何设置。</p>
<p>作者 Frank Müller，原文在此：<a href="http://mue.tideland.biz/2012/02/go-environment-setup.html?spref=tw" target="_blank">http://mue.tideland.biz/2012/02/go-environment-setup.html?spref=tw</a></p>
<p><span id="more-1245"></span></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<h1>Go 环境设置</h1>
<p>对于 Go 环境来说，最好的开始就是设置一个所有目录存放的根目录，例如 <strong>/home/themue/projects</strong>。它将是 Go SDK、第三方包和自有项目的家目录。当前的 weekly 版本可使用命令将 Go 安装到 <strong>hg clone -u weekly https://code.google.com/p/go</strong> 安装到 <strong>go</strong> 目录。 文档 <a href="http://weekly.golang.org/doc/install.html" target="_blank">http://weekly.golang.org/doc/install.html</a> 对此逐一进行了详述。另外两个目录只能手工创建，别且都分别创建 <strong>src</strong> 和 <strong>pkg</strong> 子目录。这样就得到了如下结构</p>
<pre class="brush: bash; title: ; notranslate">
/home/themue/projects
        /go
                /bin
                ...
                /test
        /own
                /pkg
                /src
        /3rdparty
                /pkd
                /src
</pre>
<p>为什么有第三方目录？新的 Go 工具采用非常智能的方式将外部包安装在不同的目录中。这是基于环境变量 <strong>$GOPATH</strong> 的。名字已经说明这是一个路径，而不仅仅是一个目录。<strong>go build</strong> 和 <strong>go install</strong> 利用 <strong>$GOPATH</strong> 寻找软件需要编译和链接的关联包。必须先安装外部包才能使用。命令 <strong>go get</strong> 将会在路径的第一个目录中安装源代码并且编译包。因此上面例子中，顺序应当为</p>
<pre class="brush: bash; title: ; notranslate">
GOPATH=$HOME/projects/3rdparty:$HOME/projects/own
</pre>
<p>当源代码安装位于 <strong>&#8230;/own/src</strong> 的自有包时，它将会被安装在 <strong>&#8230;/own/pkg</strong> 中。</p>
<p>还有哪个环境变量是必须的？一个是 <strong>$GOROOT</strong>。它指向了 Go SDK 的根目录，这里是 <strong>/home/themue/projects/go</strong>。编译后的可执行文件将会安装在 <strong>$GOROOT/bin</strong>。不过对于 SDK 会有两个选择进行接下来的设置：</p>
<ul>
<li>二进制文件存放的位置没有问题。标准的 $PATH 将指向这一目录，像这样 PATH=$PATH:$HOME/projects/go/bin.</li>
<li>另一个办法就是弄一个存放所有个人可执行文件和脚本的目录 <strong>$HOME/bin</strong>，并且将它设置在 <strong>$PATH</strong> 中。这样就可以在安装 Go 之前设置 <strong>GOBIN=$HOME/bin</strong>。那么编译的 Go 执行文件就会安装在 <strong>$HOME/bin</strong> 中。</li>
</ul>
<p>在你自己的源代码目录里，可能会需要为了不同的项目用到更多的子目录。它们命名方式可能依赖于你使用的其他软件配置管理环境。我的是 <a href="http://code.google.com./" target="_blank">code.google.com</a>。因此对于 Tideland Common Go Library（访问 <a href="http://code.google.com/p/tcgl" target="_blank">http://code.google.com/p/tcgl</a>）我将代码放在<br />
<strong>&#8230;/own/src/code.google.com/p/tcgl</strong>。这个项目包含了若干个包，无论是否在同一个项目中，都可以通过 <strong>code.google.com/p/tcgl/foo</strong> 的方式导入。更重要的是，使用我的代码的人可以更加容易的了解到如何将其作为第三方包获取和导入。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e7%8e%af%e5%a2%83%e8%ae%be%e7%bd%ae/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]go 工具</title>
		<link>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e5%b7%a5%e5%85%b7/</link>
		<comments>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e5%b7%a5%e5%85%b7/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 07:57:27 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[go tool]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[makefile]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1225</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
go 工具来了，集大成，全整合。没了 Makefile 还真有点不习惯。此文甚好，早就想翻译了，无奈最近焦头烂额……不管怎么样，还是动手了。

原文要翻墙，访问请谨慎：The go tool

&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-

<span class="readmore"><a href="http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e5%b7%a5%e5%85%b7/" title="[翻译]go 工具">阅读全文——共4892字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>go 工具来了，集大成，全整合。没了 Makefile 还真有点不习惯。此文甚好，早就想翻译了，无奈最近焦头烂额……不管怎么样，还是动手了。</p>
<p>原文要翻墙，访问请谨慎：<a href="http://areyoufuckingcoding.me/2012/02/14/the-go-tool/" target="_blank">The go tool</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>线上介绍了 go 命令的最新 weekly 发布后，我决定写一些关于它的内容。我得承认，在第一次听说统一 go 工具的时候，我满是怀疑并对此非常恐惧。我担心它会像大多数其他语言特定的包管理器一样混乱。个人认为多数这种包管理器都是在重新发明轮子，并且与操作系统的包管理器发生冲突，让系统管理员生活的更加艰辛。另外，我确实喜欢 makefile，它们简单并且直接，工作得也很好。幸运的是，新的 go 工具驱散了我的恐惧！<br />
<span id="more-1225"></span></p>
<h1>拒绝重复&#8230;</h1>
<p>最近在 <a href="http://groups.google.com/group/golang-nuts/browse_thread/thread/b4bb313b64b8ca84/4bc3cda688c04b57?lnk=gst&#038;q=the+go+command#4bc3cda688c04b57" target="_blank">go nuts</a> 邮件列表上有大量的关于新的 go 工具的信息。官方的 go 文档也包含了一些关于如何使用 go 工具<a href="http://weekly.golang.org/doc/code.html" target="_blank">编写 go 代码</a>的短文。</p>
<p>无论如何，我觉得当前在这些文档中还存在一些缺漏，因此这成为了撰写关于新的 go 工具的快速指南，并对一些技巧加以演示的理由。</p>
<h1>配置的约定</h1>
<p>这是我恐惧最大的来源，多半是因为我在 Ruby on Rails 上的经历。所有熟悉 Rails 的开发者都会同意，每当你尝试做一些微小的改进，一点点小技巧，一些不遵循规则的东西，它就……</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2012/02/meme-impossibru.jpg"><img src="http://www.mikespook.com/wp-content/uploads/2012/02/meme-impossibru.jpg" alt="" title="meme-impossibru" width="420" height="315" class="alignnone size-full wp-image-1228" /></a></p>
<p>不过还是来谈谈最佳实践吧。首先，每个 go 工具只做一件事情，并且把这件事情做得很好。例如，我们有：</p>
<ul>
<li><strong><code>go build</code></strong> &#8211; 编译包，</li>
<li><strong><code>go get</code></strong> &#8211; 解析并安装依赖，</li>
<li><strong><code>go test</code></strong> &#8211; 执行测试用例和性能测试，</li>
<li><strong><code>go install</code></strong> &#8211; 安装包，</li>
<li><strong><code>go doc</code></strong> &#8211; 生成文档，</li>
<li><strong><code>go fmt</code></strong> &#8211; 格式化代码，</li>
<li><strong><code>go run</code></strong> &#8211; 构建并执行应用，</li>
<li><strong><code>go tool</code></strong> &#8211; 调用扩展工具，</li>
<li>等等……</li>
</ul>
<p>go 包<strong>没有任何的构建配置</strong>。没有 makefile，没有依赖描述等等。那么它如何工作的？所有都是从<strong>代码</strong>中获取。为了让这个魔法生效，首先有一件事情要做。需要指定 go 那些七七八八都存在哪里。环境变量 <strong>GOPATH</strong> 定义了 go 代码树的路径。例如，下面是在 ~/.bashrc 中的：</p>
<pre class="brush: bash; title: ; notranslate">
GOPATH=&quot;/home/nu7/gocode&quot;
</pre>
<p>……告诉 go 工具你的 go 代码树存放在指定的目录中。但是你可能想知道 <strong>go 代码树到底是什么</strong>？简单说，它就是<strong>所有 go 资源、包和命令存放的地方</strong>。例如：</p>
<pre class="brush: bash; title: ; notranslate">
$ ls /home/nu7/gocode/
bin   pkg   src
</pre>
<p>所有的代码会放到 src 目录。我所说的所有的代码意味着包含你的应用、包和依赖。pkg 目录包含编译和安装后的包，而 bin 存放命令。</p>
<p>GOPATH 变量的工作方式与 PATH 类似，可以随意设置若干个 go 路径。不过务必记得其中的第一个是主要路径，因此使用 go install 安装的内容将全部存放于此。</p>
<h1>解决依赖</h1>
<p>没有用来描述依赖关系的配置文件……那么高明的 go 工具是如何判断安装什么，以及从哪里下载呢！你认为在某个地方有一个仓库？不对，没有这个！Go 带来了叫做 importpath 的东西，来看看：</p>
<pre class="brush: bash; title: ; notranslate">
import &quot;github.com/nu7hatch/gouuid&quot;
</pre>
<p>导入路径是二合一的。它是代码仓库 URL 和包将安装的本地路径。<strong>go get</strong> 工具只需要看看导入路径就知道从哪里获得依赖，而 <strong>go build</strong> 也能知道在本地从哪里导入它们。</p>
<p>为了<strong>在系统中安装依赖</strong>，必须这样使用 go get 工具：</p>
<pre class="brush: bash; title: ; notranslate">
$ go get package-name
</pre>
<p>等等，等等……这里的 package-name 是什么？这是希望安装的依赖的包的名字。假设在 go 代码中有一个叫做 foo 的包，调用 go get foo 将会安装其所有的依赖。同样可以在包中直接运行这个工具：</p>
<pre class="brush: bash; title: ; notranslate">
$ cd ~/gocode/src/foo
$ go get .
</pre>
<p>其他所有的 go 工具都是类似的方式工作，并且可以在包中直接调用，或指定导入路径。同时也可以<strong>在一组嵌套的包上使用</strong> &#8230;（三个点）通配执行命令。如果 foo 包包含一些嵌套的包，为了一次安装所有需要的依赖，只需要执行：</p>
<pre class="brush: bash; title: ; notranslate">
$ go get ./...
</pre>
<p>如果指定的依赖已经安装在了 go 代码树中，除非明确指定，否则就<strong>不会进行更新</strong>。在执行 <strong>go get</strong> 进行依赖安装的时候，增加 <strong>-u</strong> 标识进行更新：</p>
<pre class="brush: bash; title: ; notranslate">
$ go get -u package-name
</pre>
<p>很简单，不是吗？</p>
<h1>依赖的地狱！</h1>
<p>go tool 有一个约定是我特别喜欢的，不过恐怕与此同时……go 工具通过<strong>检出代码库的 HEAD 版本</strong>来解决依赖。这强制包保持<a href="http://semver.org/" target="_blank">向下兼容</a>，并且……</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2012/02/meme-jules-1.jpg"><img src="http://www.mikespook.com/wp-content/uploads/2012/02/meme-jules-1.jpg" alt="" title="meme-jules-1" width="420" height="276" class="alignnone size-full wp-image-1233" /></a></p>
<p><strong>绿色主线政策</strong>是我在工作中一直坚持的。默认分支总是首先被检出的，因此它应当<strong>保持干净</strong>，或者至少它应当<strong>可以工作</strong>！一旦官方发布，或者已经成熟，它应当同样有<strong>向下兼容的能力</strong>——总不能在补丁或者小版本上推翻或者修改 API 吧。</p>
<p>不过我们都知道在实践的时候是怎么回事。许多人像把向下兼容当作一坨屎，或把默认分支当作游乐场，等等。对于那些人，以及所有期望同新的 go 工具和平共处的开发者，我有一些建议……</p>
<div style="background: none repeat scroll 0 0 #FFFFAA; padding: 1.5em;">
<h4 style="color: #DD2222;">在该死的程序员生涯中应当遵循的守则：</h4>
<ul>
<li><strong>保持该死的主线干净！</strong></li>
<li><strong>在该死的独立分支上进行该死的新功能的开发！</strong></li>
<li>一旦你公布了代码，并且某些人使用了它，<strong>那就 TMD 不要修改 API！</strong></li>
<li>如果想要或者必须修改 API，<strong>修改 TMD 主版本号</strong> 并且 <strong>在独立于原代码库的新的代码库上进行该死的开发！</strong>
</li>
<li>如果有必要，<strong>非常有必要</strong>使用某些特别的标签，做分支或提交作为依赖，<strong>你得 TMD 用自己 fork 出来的代码库进行 TMD 所需要的提交！</strong></li>
<li>哦，还有<strong>保持简单</strong>，狗娘养的！</li>
</ul>
</div>
<p>别让我给你读以西结书（译注：《希伯来圣经》中的一部先知书）来提醒你这些……</p>
<h1>构建和安装</h1>
<p>好，让我们回到 go 命令。<strong>go build</strong> 命令用于编译包。它仅仅编译指定包，而不会进行安装。重要的是，<strong>它要求包已经检出在本地代码树中</strong>。要安装远程包应当使用 <strong>go get</strong> 来代替：</p>
<pre class="brush: bash; title: ; notranslate">
$ go get github.com/nu7hatch/gouuid
</pre>
<p>安装本地包当然使用 go install 工具。（如果有必要的话）它首先构建包然后将其安装在 $GOPATH/pkg 或者/以及 $GOPATH/bin。</p>
<p> go 工具在<strong>构建的时候也能忽略文件</strong>，无需显式的指定额外的参数或者特别的配置。对于要忽略的文件唯一要做的，就是让其名字前有一个下划线：</p>
<pre class="brush: bash; title: ; notranslate">
$ ls
_bar.go   foo.go
$ go build .
</pre>
<p>在上面的例子中，构建时 _bar.go 将会被忽略。</p>
<p>唔，就这样吧……我想关于这些也没什么好说的了，让我们继续下面的内容。</p>
<h1>用 CGO 的 C 扩展</h1>
<p>go 通过 <a href="http://http//weekly.golang.org/cmd/cgo/" target="_blank">cgo 命令</a>获得了<strong>构建 C 扩展</strong>的良好支持。实际上，编译大多数 C 支持的应用，甚至无需了解 cgo，go build 工具足够了。</p>
<p>实话说，关于 cgo 真没什么好讲的，文档和 <a href="http://code.google.com/p/go-wiki/wiki/cgo" target="_blank">go user wiki 中的文章</a>已经涵盖了大部分内容。</p>
<p>首先要说说的是那些我确实不喜欢的东西，也就是在官方例子中展示的将 C 代码写在注释中的做法。你得知道，这些例子主要是为了减少代码的尺寸并让每个例子都在同一个文件中演示。在实际的应用中 <strong>C 代码不应当放在注释部分</strong>！go build 工具能够聪明的处理包中的 .h 和 .c 文件。</p>
<p>需要一些例子？来看一个将所有参数都打印到屏幕上的简单的 echo 命令，不过要使用来自 stdio.h 的 printf 函数。与 wiki 上所述一致，<strong>go 不允许调用变长参数的 C 函数</strong>，因此需要对 printf 函数编写一个简单的包裹。代码看起来大约是这样（同样可在 <a href="http://github.com/nu7hatch/cgoecho" target="_blank">github 上</a>浏览到）：</p>
<p>echo.h：</p>
<pre class="brush: cpp; title: ; notranslate">
#ifndef _ECHO_H_
#define _ECHO_H_

#include &lt;stdio.h&gt;

void echo(char*);

#endif /* _ECHO_H_ */
</pre>
<p>echo.c：</p>
<pre class="brush: cpp; title: ; notranslate">
#include &quot;echo.h&quot;

void echo(char* s)
{
    printf(&quot;%s\n&quot;, s);
}
</pre>
<p>echo.go：</p>
<pre class="brush: cpp; title: ; notranslate">
package main

/*
#include &lt;stdlib.h&gt;
#include &quot;echo.h&quot;
*/
import &quot;C&quot;

import (
        &quot;flag&quot;
        &quot;unsafe&quot;
        &quot;strings&quot;
)

func main() {
        flag.Parse()
        cs := C.CString(strings.Join(flag.Args(), &quot; &quot;))
        C.echo(cs)
        C.free(unsafe.Pointer(cs))
}
</pre>
<p>现在可以用 go build 工具无缝的编译所有的东西。它能识别出在包中所有的 C 文件。简单来说这就能工作了！</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2012/02/meme-notbad-1.jpg"><img src="http://www.mikespook.com/wp-content/uploads/2012/02/meme-notbad-1.jpg" alt="" title="meme-notbad-1" width="420" height="304" class="alignnone size-full wp-image-1236" /></a></p>
<h1>特定平台的构建</h1>
<p>go build 另一个很酷却又有趣的地方是处理特定平台的文件。它能通过名字来识别（必须是像 file_GOOS_GOARCH.go 或者 file_GOARCH.go ）：</p>
<pre class="brush: bash; title: ; notranslate">
foo_darwin_amd64.go
foo_386.go
foo.go
</pre>
<p>这个功能对 C 文件同样适用：</p>
<pre class="brush: bash; title: ; notranslate">
foo_amd64.c
foo_386.c
foo.h
foo.go
</pre>
<p>就像文档里说的那样，你可能永远都用不到这个功能，不过我还是像给大家展示一下 go 工具在如此简单的基础上做到了多么的灵活。</p>
<p>好，但是你们当中可能有人会问，如果要做一些棘手的事情需要特殊的编译参数或者一些配置，例如……</p>
<h1>救世主 Makefile</h1>
<p>是的，不要害怕使用 makefile！这是最简便的方法来做额外的配置，一些预请求等等。makefile 不但对于 C 扩展很有帮助，对于具有多个包的应用也同样适用（例如，在 <a href="http://github.com/webrocket/webrocket" target="_blank">webrocket</a> 中使用了一个顶级的 makefile 来让任务更加轻松）。</p>
<p>更加清楚的例子……设想一个包含了内核包和基于此的命令行工具的应用。可以套用 echo 的例子，不过更加模块化：</p>
<pre class="brush: bash; title: ; notranslate">
echo/
  pkg/
    echo/
      echo.c
      echo.h
      echo.go
  cmd/
    echo/
      echo.go
</pre>
<p>希望 pkg/echo 包提供一个可重用的 C printf 函数的包裹，它的代码看起来跟前面的例子中的一样。cmd/echo 命令是一个使用了核心包来打印到屏幕的可执行文件。cmd/echo 命令是这样：</p>
<pre class="brush: cpp; title: ; notranslate">
package main

import (
        &quot;github.com/nu7hatch/cgoecho2/pkg/echo&quot;
        &quot;flag&quot;
)

func main() {
        flag.Parse()
        echo.Echo(flag.Args()...)
}
</pre>
<p><strong>注意</strong>：对于那些不了解 slice 的人来说 &#8230; 意味着将一个 slice 映射到变长参数，就像 Ruby 中的 *args。</p>
<p>回到主题，为了让对包的工作更加简单，需要一些 Makefile。看起来大约是这样：</p>
<pre class="brush: bash; title: ; notranslate">
all: echo-pkg echo-cmd

echo-pkg:
    go build ./pkg/echo

echo-cmd:
    go build ./cmd/echo
</pre>
<p>现在就可以通过调用 make 来快速的编译包和命令两个部分，还有一个很重要的，<strong>可以使用 go 命令远程安装</strong>：</p>
<pre class="brush: bash; title: ; notranslate">
$ go get github.com/nu7hatch/cgoecho2/cmd/echo
</pre>
<p>当然这时非常简单的一个例子，完全可以使用通配来进行快速的构建，而不必这么小题大作：</p>
<pre class="brush: bash; title: ; notranslate">
$ go build ./...
</pre>
<p>但是面对更大的应用，包含许多包和/或命令就会是王道了。那时有各种理由使用 makefile、shell 脚本或者任何你喜欢的构建工具。</p>
<h1>总结</h1>
<p>我不得不明确表态，我 TMD 超级喜欢新的 go 工具！在第一次用的时候，我遇到了一大堆麻烦，不过大多数都是因为我从其他包管理工具上养成的坏习惯。哈，最近我在 go-nuts IRC 上问了许多愚蠢的问题，而我想要的答案是如此的显而易见并且简单……</p>
<p>现在回顾用过的全部工具，例如 easy_install、rubygems 或者 bundler，我对它们只有一个印象……哦，我还是不要说出来了，免得许多人恨我 <img src='http://www.mikespook.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> 。取而代之，我可以向你展示我是如何看待新的 go 工具的……</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2012/02/meme-superman-1.jpg"><img src="http://www.mikespook.com/wp-content/uploads/2012/02/meme-superman-1.jpg" alt="" title="meme-superman-1" width="400" height="300" class="alignnone size-full wp-image-1237" /></a></p>
<p>看到 Go 正在向好的方向发展，我很欣慰！今天就到这里吧，好运，Gopher 们！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91go-%e5%b7%a5%e5%85%b7/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[翻译]从 r60 到 Go 1</title>
		<link>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91%e4%bb%8e-r60-%e5%88%b0-go-1/</link>
		<comments>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91%e4%bb%8e-r60-%e5%88%b0-go-1/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 04:47:59 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[go1]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[r60]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1222</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
Go1 发布的日子越来越近，Golang 社区就像将开了的山泉水一样，泊泊的不断传来各种关于 Go1 的声音。

这篇文章总结得比较完整，很清晰，随即翻译于此。

原文：http://gophersays.com/from-r60-to-go1/

<span class="readmore"><a href="http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91%e4%bb%8e-r60-%e5%88%b0-go-1/" title="[翻译]从 r60 到 Go 1">阅读全文——共2031字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>Go1 发布的日子越来越近，Golang 社区就像将开了的山泉水一样，泊泊的不断传来各种关于 Go1 的声音。<br />
这篇文章总结得比较完整，很清晰，随即翻译于此。<br />
原文：<a href="http://gophersays.com/from-r60-to-go1/" target="_blank">http://gophersays.com/from-r60-to-go1/</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分割线&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Go 1 已经到门口了，伙计们，它有<a href="http://weekly.golang.org/doc/go1.html" target="_blank">许多变化</a>！</p>
<p>这里是关于你必须知道的一些重要事情：</p>
<p><a href="#the_go_command">Go 命令</a><br />
<a href="#new_map_delete_syntax">新的 map delete 语法</a><br />
<a href="#errors_have_their_own_package">Error 有了自己的包</a><br />
<a href="#rewritten_libraries">重写的库</a><br />
<a href="#new_libraries">新的库</a><br />
<span id="more-1222"></span></p>
<h1 id="the_go_command">Go 命令</h1>
<p>Go 有了新的主命令，go，用于替换其他所有旧的 go 命令：</p>
<table>
<tbody>
<tr>
<th width="50%">以前</th>
<th width="50%">现在</th>
</tr>
<tr>
<td><code>godoc</code></td>
<td><code>go doc</code></td>
</tr>
<tr>
<td><code>gofix</code></td>
<td><code>go fix</code></td>
</tr>
<tr>
<td><code>gofmt -l -w *.go</code></td>
<td><code>go fmt</code></td>
</tr>
<tr>
<td><code>goinstall</code></td>
<td><code>go get</code></td>
</tr>
<tr>
<td><code>gorun</code></td>
<td><code>go run</code></td>
</tr>
<tr>
<td><code>gotest</code></td>
<td><code>go test</code></td>
</tr>
<tr>
<td><code>govet</code></td>
<td><code>go vet</code></td>
</tr>
<tr>
<td><code>make</code></td>
<td><code>go build</code></td>
</tr>
<tr>
<td><code>make clean</code></td>
<td><code>go clean</code></td>
</tr>
<tr>
<td><code>make install</code></td>
<td><code>go install</code></td>
</tr>
</tbody>
</table>
<p>（大多数工具命令，包括 6g/8g、6l/8l、6cov/8cov、gotype、gopprof 和 6prof/8prof 现在是 go tool。参阅 go tool 查看完整列表。）</p>
<h1>别了，Makefiles</h1>
<p>Go 1 已经摒弃了 Makefiles，不管怎么说这总是个临时的解决方案。作为替代，所有的事情——包括如何获取包；如何编译；以及如何测试——都将由源代码来直接导出，这全部都是由一个环境变量控制，GOPATH。</p>
<p>为了让 Go 1 能够编译某个包，该包必须包含在 GOPATH 的路径列表中。（如果 GOPATH 没有设置，go 使用自己的目录代替。）</p>
<ul>
<li>所有编译后的二进制<del datetime="2012-03-11T10:43:47+00:00">文剑</del>(thx joe yougy)文件存储于 GOPATH/bin</li>
<li>所有编译后的包存储于 GOPATH/pkg//</li>
<li>所有源代码存储于 GOPATH/src/</li>
</ul>
<p>这意味着如果有一个包 github.com/pmylund/helloworld，源代码应当保存于列出在 GOPATH 中的目录 src/github.com/pmylund/helloworld 下。当执行 go install，编译后的包会在这个 GOPATH 目录下的 pkg/<arch>/github.com/pmylund/helloworld 中出现。</p>
<p>由于这些新的约定，Go 唯一需要的配置就是 GOPATH。没有 Makefile，没有自定义脚本，也不用担心命名冲突。</p>
<p>这里有个用在构建和执行自有项目的例子，也可以避免外部代码搞乱项目的目录。（例如使用 go get）：</p>
<p>在 ~/.bash_aliases （或 ~/.bash_rc）中：</p>
<pre class="brush: bash; title: ; notranslate">
mygo=/home/patrick/projects/go
goroot=/home/patrick/apps/go
gobin=$goroot/bin:$mygo/bin
export GOPATH=$goroot:$mygo
export PATH=$PATH:$gobin
</pre>
<p>因为 Go 所在目录是 GOPATH 中列出的第一个文件夹，这将作为如 go get 命令使用的默认目标目录——除非你的项目已经重新设定了其他目录，否则这将作为你项目编译后的 bin 和 pkg 目录存放的地方。</p>
<p>（如果你没有 Go 目录的写权限，可以指定另一个作为默认目录来代替 goroot。go 会将所有新的第三方包安装到那里。）</p>
<p>（当你构建一个会导入某个包的项目时，例如 github.com/pmylund/helloworld，Go 会在 GOPATH 中列出的所有目录里查找。）</p>
<p>为了了解其背后的原理，可以参考 Russ Cox 发表在 golang-nuts 邮件列表上的叫做 <a href="https://groups.google.com/d/msg/golang-nuts/tLsxO2S4yoQ/V0vAiKbNw0sJ" title="The Go Command" target="_blank">The Go Command</a> 的消息。</p>
<h1 id="new_map_delete_syntax">新的 map delete 语法</h1>
<p>现在可以使用 delete(map, “key”) 来代替 map["key"] = nil, false。</p>
<h1 id="errors_have_their_own_package">Error 有了自己的包</h1>
<p>Error 从 os 移到了 errors。同样，error 现在是一个内建类型，因此无需导入任何东西就可以使用它。</p>
<table>
<tbody>
<tr>
<th width="50%">以前</th>
<th width="50%">现在</th>
</tr>
<tr>
<td><code>os.Error</code></td>
<td><code>error</code></td>
</tr>
<tr>
<td><code>os.NewError(text string) os.Error</code></td>
<td><code>errors.New(text string) error</code></td>
</tr>
<tr>
<td><code>err.String() string</code></td>
<td><code>err.Error() string</code></td>
</tr>
</tbody>
</table>
<h1>重构的库</h1>
<p>下面的表格列出了新旧包的导入路径。（所有这些都可以用 go fix 自动修复。）</p>
<h1 id="rewritten_libraries">重写的库</h1>
<table>
<tbody>
<tr>
<th>包</th>
<th>变化</th>
</tr>
<tr>
<td><code>strconv</code></td>
<td><a href="http://weekly.golang.org/doc/go1.html#strconv">明显的重构</a></td>
</tr>
<tr>
<td><code>template</code></td>
<td>用拥有全新 API 的 <code><a href="http://weekly.golang.org/pkg/text/template/">text/template</a></code> 替换</td>
</tr>
<tr>
<td><code>time</code></td>
<td><a href="http://weekly.golang.org/doc/go1.html#time">完全重新设计</a></td>
</tr>
<tr>
<td><code>url</code></td>
<td>移动到 <code>net/url</code> 并做了 <a href="http://weekly.golang.org/doc/go1.html#url">若干修改</a>，最明显的是 <code>url.URL</code> 中的 <code>URL.Raw</code> 已经移除，并且应当用 <code>URL.String()</code> 作为代替</td>
</tr>
</tbody>
</table>
<h1 id="new_libraries">新的库</h1>
<table>
<tbody>
<tr>
<th>包</th>
<th>描述</th>
</tr>
<tr>
<td><code><a href="http://weekly.golang.org/pkg/database/sql/">database/sql</a></code></td>
<td>用于操作关系数据库的标准接口（已经存在的驱动有 SQLite、MySQL、PostgreSQL 等等）</td>
</tr>
<tr>
<td><code><a href="http://weekly.golang.org/pkg/html/template/">html/template</a></code></td>
<td><code>text/template</code> 的一个 XSS-safe 封装</td>
</tr>
</tbody>
</table>
<p>这并未涵盖 Go 1 中所有的语言和包的变化。请参阅 <a href="http://weekly.golang.org/doc/go1.html" target="_blank">Go 1 发布说明</a>（仍在进行中）和 <a href="http://weekly.golang.org/doc/devel/weekly.html" target="_blank">weekly 快照历史</a>了解更多信息。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/02/%e7%bf%bb%e8%af%91%e4%bb%8e-r60-%e5%88%b0-go-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[翻译]1K 玫瑰花</title>
		<link>http://www.mikespook.com/2012/02/%e3%80%90%e7%bf%bb%e8%af%91%e3%80%911k-%e7%8e%ab%e7%91%b0%e8%8a%b1/</link>
		<comments>http://www.mikespook.com/2012/02/%e3%80%90%e7%bf%bb%e8%af%91%e3%80%911k-%e7%8e%ab%e7%91%b0%e8%8a%b1/#comments</comments>
		<pubDate>Wed, 08 Feb 2012 09:22:14 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Stardy & Research]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[rose]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1202</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
这篇文章介绍了使用 canvas 的绘图功能绘制一个 3D 玫瑰。很有特色，随翻译于此。

在 Valentine&#8217;s Day 即将来临之际，希望能给诸位死 coder 一点点好运气……

原文在此：http://www.romancortes.com/blog/1k-rose/

<span class="readmore"><a href="http://www.mikespook.com/2012/02/%e3%80%90%e7%bf%bb%e8%af%91%e3%80%911k-%e7%8e%ab%e7%91%b0%e8%8a%b1/" title="[翻译]1K 玫瑰花">阅读全文——共5559字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>这篇文章介绍了使用 canvas 的绘图功能绘制一个 3D 玫瑰。很有特色，随翻译于此。<br />
在 Valentine&#8217;s Day 即将来临之际，希望能给诸位死 coder 一点点好运气……</p>
<p>原文在此：<a href="http://www.romancortes.com/blog/1k-rose/" target="_blank">http://www.romancortes.com/blog/1k-rose/</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-翻译分隔线&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
<img class="alignright" src="http://www.romancortes.com/ficheros/rose.jpg" alt="" width="510" height="310" /><br />
我参加了 <a title="js1k" href="http://js1k.com/2012-love/" target="_blank">js1k</a> 组织的关于“爱”的第四次主题活动。提交了一个静态图片，由程序生成的 3D 玫瑰花。你可以<a href="http://js1k.com/2012-love/demo/1022" target="_blank">在这里找到它</a>。</p>
<p>它是用蒙特卡洛方法显式分段采样生成 3D 曲面。我将在这个文章中逐步解释所有的要点。<br />
<span id="more-1202"></span></p>
<h1>蒙特卡洛方法的简短说明</h1>
<p>蒙特卡洛方法是一个强大到令人难以置信的工具。我经常在各种函数最优化和采样问题中使用它，当你可以运行大量 CPU 计算，但是没有设计和编写算法的时间的时候，它们工作起来就像魔法一样。在玫瑰花的例子中，它是优化代码体积的有用工具。</p>
<p>如果你对于蒙特卡洛方法不怎么了解，可以在 Wikipedia 上阅读这篇<a href="http://en.wikipedia.org/wiki/Monte_carlo_method" target="_blank">相当棒的文章</a>。</p>
<h1>显式曲面和采样/绘制</h1>
<p>为了定义玫瑰花的形状，我使用了多种显式定义曲面。一共使用了 31 个曲面：24 个花瓣，4 个萼片（花瓣周围的小叶子），2 个叶子，还有一个用于玫瑰花的枝干。</p>
<p>那么这些显式曲面是如何工作的呢？很简单，接下来展示一个 2D 例子：</p>
<p>首先定义显式曲面函数：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {  // a 和 b 参数范围从 0 到 1。
    return {
        x: a*50,
        y: b*50
    };
    // 这个曲面将是一个 50x50 单位尺寸的正方形。
}
</pre>
<p>然后是绘制的代码：</p>
<pre class="brush: jscript; title: ; notranslate">
var canvas = document.body.appendChild(document.createElement(&quot;canvas&quot;)),
    context = canvas.getContext(&quot;2d&quot;),
    a, b, position;

// 现在将用参数 a 和 b 对曲面按照 .1 间隔进行采样：

for (a = 0; a &lt; 1; a += .1) {
    for (b = 0; b &lt; 1; b += .1) {
        position = surface(a, b);
        context.fillRect(position.x, position.y, 1, 1);
    }
}
</pre>
<p>结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-1.gif" alt="" /></p>
<p>现在，让我们尝试用密度更高的采样间隔（更小间隔 = 更高密度）：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-2.gif" alt="" /></p>
<p>你已经看到了，当采样密度越来越高时，点和点之间越来越近，直到一个点和它临近的点之间的距离小于一个像素，这时屏幕上的曲面就完全被填充了（看 0.01）。这时，无论怎样提高密度也不会带来视觉上的变化，那么刚刚绘制的的区域就是已经被填充过的（比较 0.01 和 0.001 的结果）。</p>
<p>好，现在让我们重新定义曲面函数来绘制一个圆。有各种办法来实现，我会用这个公式：(x-x0)^2 + (y-y0)^2 < radius^2 这里的 (x0, y0) 是圆心：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    var x = a * 100,
        y = b * 100,
        radius = 50,
        x0 = 50,
        y0 = 50;

    if ((x &#8211; x0) * (x &#8211; x0) + (y &#8211; y0) * (y &#8211; y0) &lt; radius * radius) {
        // 圆里
        return {
            x: x,
            y: y
        };
    } else {
        // 圆外
        return null;
    }
}
</pre>
<p>由于我屏蔽了圆外的点，所以要在采样中加入一个条件：</p>
<pre class="brush: jscript; title: ; notranslate">
if (position = surface(a, b)) {
    context.fillRect(position.x, position.y, 1, 1);
}
</pre>
<p>结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-3.gif" alt="" /></p>
<p>刚才已经说了，有各种途径来定义圆，有些无需在采样中进行屏蔽。这里会展示其中一个办法，不过仅仅是一个提示；在接下来的文章中不会使用它：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    // 使用圆的极坐标
    var angle = a * Math.PI * 2,
        radius = 50,
        x0 = 50,
        y0 = 50;

    return {
        x: Math.cos(angle) * radius * b + x0,
        y: Math.sin(angle) * radius * b + y0
    };
}
</pre>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-3.gif" alt="" /></p>
<p>（这个方法需要比前一个方法更高的采样来填充这个圆）</p>
<p>好，现在来让圆变形，这样让它看起来更像一片花瓣：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    var x = a * 100,
        y = b * 100,
        radius = 50,
        x0 = 50,
        y0 = 50;

    if ((x - x0) * (x - x0) + (y - y0) * (y - y0) &lt; radius * radius) {
        return {
            x: x,
            y: y * (1 + b) / 2 // 变形
        };
    } else {
        return null;
    }
}
</pre>
<p>结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-4.gif" alt="" /></p>
<p>好，现在这个看起来更像是玫瑰花的花瓣的形状了。我建议你对变形多进行一些调整。你可以使用任何数学函数来实现，加减乘除、sin、 cos、乘方……任何函数。尝试修改这个函数，就能得到许多的形状（有的会很有趣）。</p>
<p>现在我为其增加一些颜色，对曲面添加颜色数据：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    var x = a * 100,
        y = b * 100,
        radius = 50,
        x0 = 50,
        y0 = 50;

    if ((x - x0) * (x - x0) + (y - y0) * (y - y0) &lt; radius * radius) {
        return {
            x: x,
            y: y * (1 + b) / 2,
            r: 100 + Math.floor((1 - b) * 155), // 这会产生一个梯度
            g: 50,
            b: 50
        };
    } else {
        return null;
    }
}

for (a = 0; a &lt; 1; a += .01) {
    for (b = 0; b &lt; 1; b += .001) {
        if (point = surface(a, b)) {
            context.fillStyle = &quot;rgb(&quot; + point.r + &quot;,&quot; + point.g + &quot;,&quot; + point.b + &quot;)&quot;;
            context.fillRect(point.x, point.y, 1, 1);
        }
    }
}
</pre>
<p>结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-surface-drawing-5.jpg" alt="" /></p>
<p>铛！铛！铛！铛！隆重推出，有颜色的花瓣！</p>
<h1>3D 曲面和透视投影</h1>
<p>定义 3D 曲面是直接明了的：只要为曲面函数添加 z 属性。例如，接下来定义一个管道/圆柱体：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    var angle = a * Math.PI * 2,
        radius = 100,
        length = 400;

    return {
        x: Math.cos(angle) * radius,
        y: Math.sin(angle) * radius,
        z: b * length - length / 2, // 通过减掉 length/2，使得这个管道的中心在 (0, 0, 0)
        r: 0,
        g: Math.floor(b * 255),
        b: 0
    };
}
</pre>
<p>现在，添加透视投影，首先定义一个摄影机：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-camera.gif" alt="" /></p>
<p>我将摄影机放置于 (0, 0, cameraZ)，我将摄影机到画布的距离叫做“perspective”。我认为画布在 x/y 平面上，中心点是 (0, 0, cameraZ + perspective)。现在，每个采样点将会投影到画布：</p>
<pre class="brush: jscript; title: ; notranslate">
var pX, pY,  // 在画布上投影的 x 和 y 坐标
    perspective = 350,
    halfHeight = canvas.height / 2,
    halfWidth = canvas.width / 2,
    cameraZ = -700;

for (a = 0; a &lt; 1; a += .001) {
    for (b = 0; b &lt; 1; b += .01) {
        if (point = surface(a, b)) {
            pX = (point.x * perspective) / (point.z - cameraZ) + halfWidth;
            pY = (point.y * perspective) / (point.z - cameraZ) + halfHeight;
            context.fillStyle = &quot;rgb(&quot; + point.r + &quot;,&quot; + point.g + &quot;,&quot; + point.b + &quot;)&quot;;
            context.fillRect(pX, pY, 1, 1);
        }
    }
}
</pre>
<p>这个结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-tube1.jpg" alt="" /></p>
<h1>Z-buffer</h1>
<p>在计算机图形学中 z-buffer 是相当常见的技术，用于在远离摄影机的已经被绘制的点上绘制接近摄影机的点。它的工作方式是维护一个图像上已经画过的像素的数组。</p>
<p><img src="http://www.romancortes.com/ficheros/rose-z-buffer.jpg" alt="" /></p>
<p>这是玫瑰花的可视的 z-buffer，黑色是距离摄影机远的，白色是距离近的。</p>
<p>实现为：</p>
<pre class="brush: jscript; title: ; notranslate">
var zBuffer = [],
    zBufferIndex;

for (a = 0; a &lt; 1; a += .001) {
    for (b = 0; b &lt; 1; b += .01) {
        if (point = surface(a, b)) {
            pX = Math.floor((point.x * perspective) / (point.z - cameraZ) + halfWidth);
            pY = Math.floor((point.y * perspective) / (point.z - cameraZ) + halfHeight);
            zBufferIndex = pY * canvas.width + pX;
            if ((typeof zBuffer[zBufferIndex] === &quot;undefined&quot;) || (point.z &lt; zBuffer[zBufferIndex])) {
                zBuffer[zBufferIndex] = point.z;
                context.fillStyle = &quot;rgb(&quot; + point.r + &quot;,&quot; + point.g + &quot;,&quot; + point.b + &quot;)&quot;;
                context.fillRect(pX, pY, 1, 1);
            }
        }
    }
}
</pre>
<h1>旋转圆柱体</h1>
<p>你可以使用任何向量旋转方法。在玫瑰花的例子中，我使用 <a href="http://en.wikipedia.org/wiki/Euler_angles" target="_blank">Euler 旋转</a>。来实现一个基于 Y 轴的旋转：</p>
<pre class="brush: jscript; title: ; notranslate">
function surface(a, b) {
    var angle = a * Math.PI * 2,
        radius = 100,
        length = 400,
        x = Math.cos(angle) * radius,
        y = Math.sin(angle) * radius,
        z = b * length - length / 2,
        yAxisRotationAngle = -.4, // in radians!
        rotatedX = x * Math.cos(yAxisRotationAngle) + z * Math.sin(yAxisRotationAngle),
        rotatedZ = x * -Math.sin(yAxisRotationAngle) + z * Math.cos(yAxisRotationAngle);

    return {
        x: rotatedX,
        y: y,
        z: rotatedZ,
        r: 0,
        g: Math.floor(b * 255),
        b: 0
    };
}
</pre>
<p>结果为：</p>
<p><img src="http://www.romancortes.com/ficheros/rose-tube2.jpg" alt="" /></p>
<h1>蒙特卡洛采样</h1>
<p>在文章中已经使用了基于间隔的采样。它需要对每个曲面设定合适的间隔。如果间隔大，渲染会很快，但是曲面可能未被完全填充而存在空洞。另一方面，如果间隔过小，渲染会超过透视投影所需的时间。</p>
<p>所以，还是切换到蒙特卡洛采样吧：</p>
<pre class="brush: jscript; title: ; notranslate">
var i;

window.setInterval(function () {
    for (i = 0; i &lt; 10000; i++) {
        if (point = surface(Math.random(), Math.random())) {
            pX = Math.floor((point.x * perspective) / (point.z - cameraZ) + halfWidth);
            pY = Math.floor((point.y * perspective) / (point.z - cameraZ) + halfHeight);
            zBufferIndex = pY * canvas.width + pX;
            if ((typeof zBuffer[zBufferIndex] === &quot;undefined&quot;) || (point.z &lt; zBuffer[zBufferIndex])) {
                zBuffer[zBufferIndex] = point.z;
                context.fillStyle = &quot;rgb(&quot; + point.r + &quot;,&quot; + point.g + &quot;,&quot; + point.b + &quot;)&quot;;
                context.fillRect(pX, pY, 1, 1);
            }
        }
    }
}, 0);
</pre>
<p>现在，参数 a 和 b 被设置为两个随机值。对足够多的点进行采样，曲面就可以利用这种方法填充。多亏了间隔采样，我可以确定每次用 10000 个点绘制，然后更新屏幕。</p>
<p>特别说明一下，完全填充一个曲面仅仅需要保证伪随机数生成器的品质够好。在某些浏览器中，Math.random 是按照<a href="http://en.wikipedia.org/wiki/Linear_congruential_generator" target="_blank">线性一致生成器</a>实现的，而这可能在某些曲面上产生一些问题。如果你在采样中有较好的伪随机噪声生成的需求，你可以使用更高品质的如 Mersenne Twister （这里有其 JS 实现），或者在某些浏览器里可以使用的密码随机生成器。同样使用<a href="http://en.wikipedia.org/wiki/Low-discrepancy_sequence" target="_blank">低差异数序列</a>也是很好的解决方案。</p>
<h1>总结</h1>
<p>为了完成这个玫瑰花，花朵的每个部分，每个曲面，需要同时进行渲染。我为函数添加了第三个参数用于确定返回玫瑰花的哪个部分的点。数学上来说，这是一个分段函数，每个片段对应玫瑰花的一部分。在花瓣的部分，我使用旋转和拉伸/变形来创建所有花瓣。所有都是用文章中提及的方法混合来完成的。</p>
<p>当然通过采样建立显式曲面是众所周知的方法，并且是最古老的 3D 图形方法之一，在艺术用途中像我这样使用分段/蒙特卡洛/z-buffer 已经非常少见了。没什么创新，对于实际生活也不怎么有用，但是非常适合 js1k 这种简单并且小尺寸的要求。</p>
<p>通过这篇文章，我希望能够激发读者在计算机图形学上的兴趣来进行尝试，并且在不同的渲染方法中找到乐趣。在图形学的世界中探索和玩耍是一件令人兴奋的事情。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/02/%e3%80%90%e7%bf%bb%e8%af%91%e3%80%911k-%e7%8e%ab%e7%91%b0%e8%8a%b1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]Goroutine性能测试</title>
		<link>http://www.mikespook.com/2012/01/goroutine%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95/</link>
		<comments>http://www.mikespook.com/2012/01/goroutine%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95/#comments</comments>
		<pubDate>Fri, 06 Jan 2012 03:55:10 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Golang]]></category>
		<category><![CDATA[golang]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[翻译]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1177</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
原文在此：http://en.munknex.net/2011/12/golang-goroutines-performance.html

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;翻译分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;

概述

<span class="readmore"><a href="http://www.mikespook.com/2012/01/goroutine%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95/" title="[翻译]Goroutine性能测试">阅读全文——共1952字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p>原文在此：<a href="http://en.munknex.net/2011/12/golang-goroutines-performance.html" target="_blank">http://en.munknex.net/2011/12/golang-goroutines-performance.html</a></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;翻译分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<h1>概述</h1>
<p>在这篇文章里，我将尝试评估 goroutine 的性能。goroutine 是类似轻量级线程的东西。为了提供原生的多任务，它（协同 channel 一起）被内建于Go中。</p>
<p>文档告诉我们：</p>
<blockquote><p>它实际上是在同一个地址空间里创建成百上千个 goroutine。</p></blockquote>
<p>因此，这个文章的重点就是测试并明确在如此巨大的并发运行函数的情况下所能承受的性能压力上限。<br />
<span id="more-1177"></span></p>
<h1>内存</h1>
<p>创建一个新的goroutine所需空间并未记录在文档中。只是说需要几千字节。在不同的机制下测试，帮助确认这个数值为4—4.5kB。因此，5GB差不多足够运行一百万个goroutine。</p>
<h1>性能</h1>
<p>让我们算算在一个 goroutine 里运行函数会损失多少的性能吧。可能你已经知道这非常简单——只要在函数调用前添加 go 关键字：</p>
<pre class="brush: cpp; title: ; notranslate">
go testFunc()
</pre>
<p>goroutine 复用于线程。默认情况下，如果没有设定 GOMAXPROCS 环境变量，程序只使用一个线程。为了利用全部 CPU 内核，则必须制定它的值。例如：</p>
<pre class="brush: bash; title: ; notranslate">
export GOMAXPROCS=2
</pre>
<p>这个值在运行时使用。因此没有必要在每次修改这个值之后，重新编译程序。</p>
<p>以我的推断，大多数时间花费在创建 goroutine，切换它们，以及从一个线程迁移 goroutine 到另外的线程，还有在不同的线程之间的 goroutine 进行通讯。为了避免无尽的论述，让我们从仅用一个线程的情况开始。</p>
<p>所有测试都是在我的 nettop（译注：英特尔公司的低成本简易台式机解决方案）上完成的：</p>
<ul>
<li>Atom D525 Dual Core 1.8 GHz</li>
<li>4Gb DDR3</li>
<li>Go r60.3</li>
<li>Arch Linux x86_64</li>
</ul>
<h1>方法</h1>
<p>这是测试函数生成器：</p>
<pre class="brush: cpp; title: ; notranslate">
func genTest (n int) func (res chan &lt;- interface {}) {
        return func(res chan &lt;- interface {}) {
                for i := 0; i &lt; n; i++ {
                        math.Sqrt(13)
                }
                res &lt;- true
        }
}
</pre>
<p>然后这里是一系列分别计算 sqrt(13) 1、10、100、1000 和 5000 次的函数集合：</p>
<pre class="brush: cpp; title: ; notranslate">
testFuncs := [] func (chan &lt;- interface {}) { genTest(1), genTest(10), genTest(100), genTest(1000), genTest(5000) }
</pre>
<p>我将每个函数在循环中执行 X 遍，然后在 goroutine 中执行 X 遍。然后比较结果。当然，应当留意垃圾回收。为了降低其带来的影响，我在 goroutine 结束后显式调用了 runtime.GC() 并记录结束时间。当然，为了测试精确性，每个测试执行了许多遍。整个运行时间用了大约 16 小时。</p>
<h1>一个线程</h1>
<pre class="brush: bash; title: ; notranslate">
export GOMAXPROCS=1
</pre>
<p><img src="https://lh4.googleusercontent.com/-tJyRcozfSi4/Tv4c-32C8LI/AAAAAAAABmw/2eBz0cWFWaw/s980/BOlyT.png" alt="goroutine 性能测试 1.1" /></p>
<p>图表显示在 goroutine 中运行的 sqrt() 计算工作大约比在函数中运行慢四倍。</p>
<p>来看看剩余的四个函数的情况：</p>
<p><img src="https://lh3.googleusercontent.com/-SdI6VAsosG0/Tv4c9x9NpDI/AAAAAAAABmo/c6EVJs4scHY/s983/bdJiZ.png" alt="goroutine 性能测试 1.2" /></p>
<p>你会注意到，即使并发执行70万 goroutine 也不会使得性能下降到 80% 以下。现在是最值得敬佩的地方。从 sqrt()x1000 开始，总体消耗低于 2%。5000 次——只有 1%。看起来这个数值与 goroutine 的数量无关！因此唯一的制约因素是内存。</p>
<h1>概要：</h1>
<p>如果互不依赖的代码的执行时间高于计算平方跟的10倍，并且你希望它并发执行，应毫不犹豫的让其在 goroutine 中运行。虽然，可以轻松的将10或者100个这样的代码放在一起，不过损失的性能仅仅分别是 20% 和 2%。</p>
<h1>多线程</h1>
<p>现在来看看当我们希望使用若干个处理器内核时的情况。在我的用例中是 2 个：</p>
<pre class="brush: bash; title: ; notranslate">
export GOMAXPROCS=2
</pre>
<p>再次执行我们的测试程序：</p>
<p><img src="https://lh3.googleusercontent.com/--Oopi4ZD_BU/Tv4c8s6C7JI/AAAAAAAABmg/i6I2GFF6JeI/s977/zcv7K.png" alt="goroutine 性能测试 2.1" /></p>
<p>这里你会发现，尽管内核数增加了一倍，但是前两个函数的运行时间却增加了！这极可能是在线程之间移动比执行它们的开销要大得多。：）当前的调度器还不能处理，不过 Go 的开发者承诺在未来会解决这种情况。</p>
<p><img src="https://lh4.googleusercontent.com/-f7R2zsoajNI/Tv4c7W6Um4I/AAAAAAAABmY/qY6C6eYQOzI/s981/Jp3lZ.png" alt="goroutine 性能测试 2.2" /></p>
<p>你已经看到了，最后的两个函数完全使用了两个核。在我的 nettop 上，他们的执行时间分别是 ~45µs 和 ~230µs。</p>
<h1>总结</h1>
<p>尽管这是一个年轻的语言，并且有着一个临时的调度器实现，goroutine 的性能让人觉得兴奋。尤其是与 Go 的简单易用结合起来的时候。这令我印象深刻。感谢 Go 开发团队！</p>
<p>当运行时间少于 1µs 我会在执行 goroutine 之前深思熟虑一下，而如果运行时间超过 1ms，那就决不犹豫的使用 goroutine 了。：）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2012/01/goroutine%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我们要什么样的.NET程序员</title>
		<link>http://www.mikespook.com/2011/12/%e6%88%91%e4%bb%ac%e8%a6%81%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84-net%e7%a8%8b%e5%ba%8f%e5%91%98/</link>
		<comments>http://www.mikespook.com/2011/12/%e6%88%91%e4%bb%ac%e8%a6%81%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84-net%e7%a8%8b%e5%ba%8f%e5%91%98/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 04:47:13 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[My life]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[团队]]></category>
		<category><![CDATA[扯淡]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=1170</guid>
		<description><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
外刊IT评论今天抽风，发了很久以前的一篇博文的译文出来：《为什么我们不要.NET程序员》。本文一发，各种口水接踵而至。这篇文章实际上是《CEO Friday: Why we don’t hire .NET programmers》的译文，原文作者在发文后的两天的时间里不断的根据读者反馈对文章进行了更新和补充。但是遗憾的是外刊IT评论却未能翻译完整（不，不，你们不要指望我会翻译剩下的部分，我对此毫无兴趣。），这使得这篇很有闪光点的文章立刻变成了“孰优孰劣”的口水文章了。

看看中文翻译后的评论吧：

<span class="readmore"><a href="http://www.mikespook.com/2011/12/%e6%88%91%e4%bb%ac%e8%a6%81%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84-net%e7%a8%8b%e5%ba%8f%e5%91%98/" title="我们要什么样的.NET程序员">阅读全文——共2236字</a></span>]]></description>
			<content:encoded><![CDATA[<style type="text/css">
#leftcontainerBox {
	float:left;
	position: fixed;
	top: 60%;
	left: 70px;
}
#leftcontainerBox .buttons {
	float:left;
	clear:both;
	margin:4px 4px 4px 4px;
	padding-bottom:2px;
}
#bottomcontainerBox {
	width: 50%;
	padding-top: 1px;
}
#bottomcontainerBox .buttons {
	float: left;
	margin: 4px 4px 4px 4px;
}
</style>
<p><a href="http://www.aqee.net/" target="_blank">外刊IT评论</a>今天抽风，发了很久以前的一篇博文的译文出来：《<a href="http://www.aqee.net/why-we-dont-hire-net-programmers/" target="_blank">为什么我们不要.NET程序员</a>》。本文一发，各种口水接踵而至。这篇文章实际上是《<a href="http://blog.expensify.com/2011/03/25/ceo-friday-why-we-dont-hire-net-programmers/" target="_blank">CEO Friday: Why we don’t hire .NET programmers</a>》的译文，原文作者在发文后的两天的时间里不断的根据读者反馈对文章进行了更新和补充。但是遗憾的是外刊IT评论却未能翻译完整（不，不，你们不要指望我会翻译剩下的部分，我对此毫无兴趣。），这使得这篇很有闪光点的文章立刻变成了“孰优孰劣”的口水文章了。</p>
<p>看看中文翻译后的评论吧：</p>
<blockquote><p>有一种人，自己写不出东西，就怪能写出东西的人使用的工具太先进</p>
<p>弱智文章</p>
<p>SB文章，还以为有什么高深的见解，完全是个自以为是的家伙。至多不过是了解了.net之外某一些东西，对自己完全不了解的东西大放厥词还放出优越感来了。</p>
<p>俺作为一名.NET程序员，鉴定结果为，“此文纯属标题党”，一笑而过~~~</p></blockquote>
<p>我对留下这些评论的程序员感到悲哀……</p>
<p>我们的团队也有着大量的.NET工程师，我每天与他们共处。他们中间有聪明的、优秀的、稳重的工程师；也有躁动的、浮夸的、随意的编码人员。他们能够产生符合设计规范和要求的代码和系统；也会在不经意之间向系统引入致命 bug 而导致生产环境的崩溃。他们其实与依赖其他技术架构的程序员并无多大的不同。</p>
<p><span id="more-1170"></span></p>
<p>早上，我看到那篇中文翻译的时候，在公司的讨论组里向大家分享了译文和原文。特别提示了，重点看看原文后面的评论。发出去后，我本以为会有人回应支持或者反对。但是没有任何一个人对那些内容进行赞扬或者批评。后来，一个比较了解我的同事私下跟我说“估计一大部分人心里不是滋味”，“一下看到标题，还有你的身份”。好吧，可能许多人心里十分不悦，但是碍于我的“身份”不便表露？我毫不介意的跟大家分享一下，我在国家正式的定义中的身份是“群众”。</p>
<p>我不知道会有多少团队的成员看到本文，我也无从知道他们真实的想法。不过，我可以谈谈什么样的.NET程序员是我们需要.的。</p>
<p>当然为了避免在我的博客上有人指责我由于“根本不了解.NET技术，也不懂windows平台，没有资格来说三道四”。我简要介绍一下我对windows平台和.NET的了解情况。</p>
<p>跟大部分人一样，我对计算机和IT的认识是从windows开始的。win32.hlp 这个帮助文件我想大部分年轻的.NET程序员从来没看过，甚至从来没听过。COM/COM+对于.NET平台就像战国时代的二轮马车一样遥远。PE文件结构就是放在博物馆里的竹简一般，除了历史学家会感兴趣之外毫无用处……我能举的例子还有很多，而这些在我被开源和 Linux 这个魔鬼抓去之前，是每日在学习和探索的东西。哦，忘记说了，.NET 我也不算是毫无认知。至少，在有史可查的范围内，我开源了国内第一个用C#编写的针对性SQL Injection自动化注入工具，如果没记错，那是01还是02年左右的时间。好吧，现在我是否有资格来跟大家探讨这个事情了呢？</p>
<p>事情还是从如何做出一个1.7盎司的汉堡说起……</p>
<p>作为一个.NET程序员，或者特指正在进行互联网开发的.NET程序员，你是否知道我们面对的不仅仅是1.6盎司、1.7盎司的汉堡这么简单的事情？你是否知道互联网这场盛宴不仅仅是做一两个汉堡这么简单？思考的方式有许多种，你是否陷入了做汉堡需要在哪里获得合适的面包、肉饼、洗好的蔬菜、酱料的迷题中，而忘记了手边就有面粉、烤炉，冰箱里有冷藏的鲜肉（你看，已经无需自己杀猪宰牛了），放在窗台的蔬菜上面的泥土和青虫说明菜叶相当的新鲜。</p>
<p>换句话说：你们是否陷入过疯狂的在.NET库中寻找一个合适的类，而忘记去看看开源社区或者第三方是否有提供更好的服务？是否执意要在微软提供的架构体系下实现一些特别的需求，其实那些需求只要一些跳出框架的小小的技巧？是否在看到业内的某些关于技术创新的一句话新闻时，就在心中暗想“这有什么先进的，.NET早有了”，而没有深入的研究为什么这一创新能够成为业内的新闻？</p>
<p>当然，如果对于这些你都有自己可以解释的答案，那么你或许是我们所需要的那种.NET程序员！</p>
<p>如果：你不但能够使用服务器端控件，还能说出其封装的底层原理；不但能够在IIS里建立应用，还能弄明白从客户在浏览器输入你的应用的地址，到他得到满意的结果，这中间每个环节隐含的细节；不但会用WCF来实现功能，也清晰的理解其中的缘由，尤其的，清晰的了解SOA应用于互联网的利弊；不但会在MSDN中查询疑难问题，也会在Google中参考出现在Mono中的类似的解决办法。</p>
<p>那么你应该是我们所需要的那种.NET程序员！</p>
<p>当然，更为优秀的，是那些能够在.NET框架下开发，却从不自称为.NET程序员的家伙们。他们不会将自己限定在某种技术、某种平台；他们热爱技术，热爱生活；他们有着像猫一样的好奇心，即便是这好奇心可能杀死他们也从不畏惧，他们同样有九条命；他们乐于钻研.NET技术，但是也会吸取其他平台的精华……</p>
<p>对于这样的人，我知道是可遇不可求的……</p>
<p>.NET、JAVA、PHP、Python……这些技术难道就没有一点贯通的地方？难道我们在自我介绍的时候不能换个说法：</p>
<blockquote><p>我，是程序员，在现在这个阶段我对.NET的使用积累的经验更多一些。</p></blockquote>
<p>是的，我正是这个意思，程序员可以有各种标签，但是别让标签左右了工程师的灵魂。做技术的主人还是奴隶，只是个人的选择而已。</p>
<p>这或许能够阐述我们要什么样的.NET程序员了吧？</p>
<p>我们需要的是熟悉.NET的程序员，我们真得不要“.NET程序员”。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/2011/12/%e6%88%91%e4%bb%ac%e8%a6%81%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84-net%e7%a8%8b%e5%ba%8f%e5%91%98/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
<!-- This Quick Cache file was built for ( sfjslfksdafj www.mikespook.com/feed/ ) in 0.70961 seconds, on May 18th, 2012 at 2:24 am UTC. -->
<!-- This Quick Cache file will automatically expire ( and be re-built automatically ) on May 18th, 2012 at 3:24 am UTC -->
<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- Quick Cache Is Fully Functional :-) ... A Quick Cache file was just served for ( sfjslfksdafj www.mikespook.com/feed/ ) in 0.00047 seconds, on May 18th, 2012 at 3:12 am UTC. -->
