Scala 中的协变和逆变

Java 数组

先来看一个 Java 中的例子,Java 中的数组是协变的。也就是说,一个 String 数组(String[])是可以被当成 Object 数组(Object[])处理的:

String[] a1 = { "abc" };
Object[] a2 = a1;

这种协变虽然在读取数组内容时不会有问题(a1 数组中的 String 元素可以被当成 Object 使用),但是修改数组内容时就会出现无法在编译期检测出来的错误了:

a2[0] = new Integer(17)
String s  = a1[0]  // java.lang.ArrayStoreException
阅读全文 →

存储是移动应用性能的瓶颈?

Revisiting Storage for Smartphones 是今年 FAST 会议上的最佳论文,这篇论文提出了一个违背直觉的观点,很有意思。这里简单介绍一下这篇论文的内容,有兴趣的朋友可以直接访问前面的链接下载原文或是观看现场录像。

传统的观点认为,移动应用性能的主要瓶颈在网络和 CPU,而闪存的读写速率明显高于网络传输速度,不会成为性能的瓶颈。然而,根据上图作者给出的关于移动存储性能的图例(纵坐标单位为 Mbps,本文图片均来自演讲 slides 和原论文),我们可以看到,虽然移动存储顺序读写的性能明显高于 wifi 和 3G,但是随机写的性能却比它们差很多,因此移动存储成为应用性能瓶颈是完全有可能的。

阅读全文 →

用 Git 管理命令行配置

以前部署新机器时都要把一堆配置文件 scp 过去,今天折腾了下用 Git 统一管理这些配置文件。

做起来很简单,创建一个 dotfiles 目录,把所有要同步的配置文件都放到这个目录下,并重命名去掉文件名开头的点,以免被 Git 忽略。写了一个脚本链接这些配置文件到 HOME 目录:

#!/usr/bin/env ruby

safe_mode = ARGV.include? '--safe'

files = %w(zshrc tmux.conf gitconfig vimrc emacs gitignore_global LS_COLORS)
files.each do |file|
  unless safe_mode and File.exists?("#{ENV['HOME']}/.#{file}")
    %x(ln -s -i -v $PWD/#{file} ~/.#{file})
    puts ".#{file} linked" if safe_mode
  end
end
阅读全文 →

利用 ETag 优化 Rails 应用

ETag 是 HTTP 协议的一部分,可以用来检测客户端的缓存是否仍然有效。不少网站都实现了对 ETag 的支持,在 HTTP 响应头中加入当前传送内容的 ETag。以 heroku.com 为例:

$ curl -I www.heroku.com
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 17 Feb 2012 17:36:44 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Etag: "f74bb78aa48d36e6a0b2072a131b20b9"
Cache-Control: public, max-age=300
Content-Length: 15481
阅读全文 →

转换 Visio 图片为 EPS 格式

Windows 7 及 Visio 2010 下验证可行:

  • 添加本地打印机,类型选择 Generic -> MS Publisher Color Printer
  • 在 Visio 中打印,选择新添加的打印机,选中 Print to file,点 Properties -> Advanced
  • Document Options -> PostScript Options -> PostScript Output Option 中,选择 Encapsulated PostScript (EPS)
  • 保存时别忘了加后缀名 .eps
阅读全文 →

一些 ZvT 的心得

一直在国服大师组混,最让我头疼,同时研究的也最多得对战就是 ZvT 了。这里写一点自己关于 ZvT 的心得,欢迎探讨。

阅读全文 →

转用 octopress 了

jekyll 是一个静态博客生成工具,可配置性很强。但是它的配置对于初学者不是很友好,没有现成的模版,需要自己从头搭一个。octopress 大大简化了这一配置过程,在 jekyll 的基础上提供了一个默认主题,以及一些常用的插件。 Why 在 github 上捣鼓了一阵子 octopress 后,决定把原来的 wordpress 博客的数据转移到这个 octopress 博客上了。相对于 wordpress,octopress 的优点在于: 支持 Markdown 语法。Markdown 是 github、stackoverflow 上的默认标记语言,写笔记我也一直用这个。Mac 平台上有不少好用的 Markdown 编辑器,例如收费的 Byword,免费的 Mou,这些工具都增加了写日志时的愉悦感。 静态。对主页空间没有要求,甚至放到 github pages 上都可以。静态页面如果要加评论,可以考虑 disqus 等第三方 JS 工具。 对内嵌代码支持很好。内置了 pygments ,这里有一份支持语言的列表。值得一提的是 octopress 还支持内嵌 Gist。 日志文件都在本地,而且是纯文本,管理很方便(可以用 git),也不用担心租用的服务器数据丢失等问题。 rake new_post; rake gen_deploy 这样写博客很过瘾 :) How 关于 wordpress 到 octopress 的数据转移,本文结尾的两篇参考文章已经说得很详细了,这里再补充几点: 编码:jekyll 的 wordpressdotcom. 阅读全文 →

ActiveRecord 的一些细节

对象属性 ActiveRecord 对象在数据库中的属性并不是以实体变量的方式保存的,如果要为一个属性设置默认值的话, class Item < ActiveRecord::Base def category @category || 'n/a' end end 这样的实现是不可行的。读取和修改这些属性时应该使用 read_attribute 和 write_attribute: class Item < ActiveRecord::Base def category read_attribute(:category) || 'n/a' end end Hash 和相等性 ActiveRecord 的 hash 值是根据主键的值计算出来的,这就意味着未保存对象的 hash 值是不可靠的。同样两个 model 对象的相等比较(即==操作符)也是基于主键的,所以两个 model 对象即使它们的其他属性不一样,仍有可能被当作相等。 查找 find_by_attribute 方法后面加个 ! 号,即使用 find_by_attribute!,就能在找不到对象的时候触发一个 RecordNotFound 异常,而不是返回 nil。 find_or_initialize_by 和 find_or_create_by 也是两个好用的方法,它们在找不到对象时分别使用 new 和 create 新建一个,并用查找的属性初始化新建的对象。 手写 SQL 不得不手写 SQL 同时又要防止注入攻击的一个比较简洁的写法是 Order.where("name = :name and pay_type = :pay_type", params[:order]) 回调函数 出于性能考虑,after_find 和 after_initialize 只能通过函数声明的方式定义,即不能用类似 before_validation :normalize_fields 这样的形式。 阅读全文 →

Rails 中 render 方法的可选参数

:content_type 设置返回内容的 MIME 类型 render :file => filename, :content_type => 'application/rss' :layout 指定 layout :status 指定返回的 HTTP 代码 :location 指定 HTTP 头中的 Location 字段 Rails 生成的 controller 代码中,create.json 方法在生成对象后会将 Location 设置为新生成对象的 json 地址: respond_to do |format| if @item.save format.html { redirect_to @item, notice: 'Item was successfully created.' } format.json { render json: @item, status: :created, location: @item } else format.html { render action: "new" } format.json { render json: @item.errors, status: :unprocessable_entity } end end 参考:http://guides. 阅读全文 →

REST 服务的方法

HEAD 方法和 GET 方法比较像,但是它不返回对象的实际表示,只返回一个 HTTP 头。HEAD 可以用来查看对象修改时间、大小等信息,Amazon S3 的客户端就用它来读取文件元信息。 用 PUT 和 POST 创建对象时的一个区别在于,使用前者时客户端知道被创建对象的 URL(例如 /items/3),而后者则不需要客户端了解(例如 /items/new)。 OPTIONS 用来查看客户端对某个资源有那些可用的操作。 正确的设计应当保证: GET 和 HEAD 是安全的,即不会修改任何对象状态。多次调用它们的结果应当和只调用一次甚至不调用一样。 GET、HEAD、PUT 和 DELETE 方法是幂等(idempotent)的。多次调用它们的结果应当和只调用一次一样。 这两点保证了在一个不可靠的网络中,客户端仍能进行有效的操作。 参考:Restful Web Services 阅读全文 →