<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>luikore (Zete)</title>
    <link>https://ruby-china.org/luikore</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>torch.rb 看起来不错，用 Ruby 搞深度学习也能走上正统了</title>
      <description>&lt;p&gt;感谢 PyTorch 做了 libTorch，它是个建构在 Eigen / ATen 之上的 C++ 库，然后 Ruby 只要做个绑定包装就可以使用了。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ankane/torch.rb" rel="nofollow" target="_blank"&gt;https://github.com/ankane/torch.rb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;缺点也有，就是 Ruby namespace 四个点，不如 Python 的一个点好看。用前 include 好了。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;libtorch automake
&lt;span class="c"&gt;# rice 需要 --enabled-shared&lt;/span&gt;
&lt;span class="nv"&gt;RUBY_CONFIGURE_OPTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--enable-shared"&lt;/span&gt; rbenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; 2.8.0-dev
&lt;span class="c"&gt;# 感觉 rice 没搞对 clang 的一些默认 flag&lt;/span&gt;
&lt;span class="nv"&gt;CXX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'clang++ -std=c++11 -fdeclspec'&lt;/span&gt; gem ins rice
gem ins torch-rb
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luikore</author>
      <pubDate>Wed, 12 Aug 2020 18:00:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/40270</link>
      <guid>https://ruby-china.org/topics/40270</guid>
    </item>
    <item>
      <title>一道题解</title>
      <description>&lt;p&gt;问题是这样的 (1977 年第 19 届 IMO)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;在一个有限项的实数序列中，任意的相连 7 项之和 &amp;lt; 0，任意的相连 11 项之和 &amp;gt; 0。求这种序列最多有几项。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;竞赛题解网上有，就不表了…… 这里用程序蛮力解决。&lt;/p&gt;

&lt;p&gt;显然这些约束都可以写成线性规划约束，用单纯形法求解。&lt;/p&gt;

&lt;p&gt;我们考虑小一个层级的问题：任意相连 2 项之和 &amp;lt; 0，任意相连 4 项 &amp;gt; 0，那这个问题写成 GMPL 程序会是这样：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var x0;
var x1;
var x2;
var x3;
s.t. c1: 1*x0 + 1*x1 + 0*x2 + 0*x3 &amp;lt;= -0.1;
s.t. c2: 0*x0 + 1*x1 + 1*x2 + 0*x3 &amp;lt;= -0.1;
s.t. c3: 0*x0 + 0*x1 + 1*x2 + 1*x3 &amp;lt;= -0.1;
s.t. c4: 1*x0 + 1*x1 + 1*x2 + 1*x3 &amp;gt;= 0.1;
solve;
display x0,x1,x2,x3;
end;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果有解，那执行 &lt;code&gt;glpsol --math problem.mod&lt;/code&gt; 输出里会显示一行 "OPTIMAL LP SOLUTION FOUND".&lt;/p&gt;

&lt;p&gt;于是我们从长度为 11 的序列开始生成 GMPL 程序，解解看到多长以后没有解，就能得出答案了。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;feasible?&lt;/span&gt; &lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
  &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"var &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rgt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;lft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt; &lt;span class="s2"&gt;" + "&lt;/span&gt;
    &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"s.t. c&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lft&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rgt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"solve;"&lt;/span&gt;
  &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"display &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;
  &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"end;"&lt;/span&gt;

  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt; &lt;span class="s1"&gt;'problem.mod'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'w'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;problem&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`glpsol --math problem.mod`&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exitstatus&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"problem failed"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'OPTIMAL LP SOLUTION FOUND'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;
&lt;span class="n"&gt;short&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;span class="n"&gt;last_feasible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;vars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;
  &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;# short consecutives: &amp;lt;= -0.1&lt;/span&gt;
  &lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_cons&lt;/span&gt; &lt;span class="n"&gt;short&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s1"&gt;'&amp;lt;= -0.1'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# positive long consecutives: &amp;gt;= 0.1&lt;/span&gt;
  &lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_cons&lt;/span&gt; &lt;span class="n"&gt;long&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;gt;= 0.1'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;var_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;"x&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;feasible?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Feasible: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;last_feasible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Longest sequence: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;last_feasible&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;程序输出（秒解）：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Feasible: 11
Feasible: 12
Feasible: 13
Feasible: 14
Feasible: 15
Feasible: 16
Longest sequence: 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以满足题目条件的序列最多有 16 项。&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Mon, 24 Feb 2020 10:55:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/39531</link>
      <guid>https://ruby-china.org/topics/39531</guid>
    </item>
    <item>
      <title>Ruby 2.6 无限 Range</title>
      <description>&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array[1..]
(1..).each {|i| puts i }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="https://bugs.ruby-lang.org/issues/12912" rel="nofollow" target="_blank"&gt;https://bugs.ruby-lang.org/issues/12912&lt;/a&gt;&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Fri, 20 Apr 2018 09:43:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/35496</link>
      <guid>https://ruby-china.org/topics/35496</guid>
    </item>
    <item>
      <title>TimescaleDB 做了个新主页</title>
      <description>&lt;p&gt;这下应该会火吧？&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.timescale.com/" rel="nofollow" target="_blank"&gt;http://www.timescale.com/&lt;/a&gt;&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Fri, 11 Aug 2017 19:03:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/33805</link>
      <guid>https://ruby-china.org/topics/33805</guid>
    </item>
    <item>
      <title>Startcom 证书已经不靠谱</title>
      <description>&lt;p&gt;Startcom 被 wosign 悄悄收购&lt;/p&gt;

&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=12411870" rel="nofollow" target="_blank"&gt;https://news.ycombinator.com/item?id=12411870&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;还发了假的 github 证书&lt;/p&gt;

&lt;p&gt;现在我已经把 Startcom / StartSSL 根证书全 revoke 了 (还得重新生成
但 Ruby China 貌似在 Startcom 注册的...&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Tue, 06 Sep 2016 10:10:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/30993</link>
      <guid>https://ruby-china.org/topics/30993</guid>
    </item>
    <item>
      <title>Cjsx 还是挺好使的...</title>
      <description>&lt;p&gt;webpack.config.js 加入 cjsx-loader&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RACK_ENV&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DefinePlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;process.env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"production"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// reduce react size&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;optimize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UglifyJsPlugin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HotModuleReplacementPlugin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;loaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;cjsx$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;production&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coffee!cjsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hot!coffee!cjsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;匿名 class&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt; &lt;span class="s"&gt;'react'&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Component&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comprehension 渲染数组，比 Array.map 更有效率，比 for 循环 push 更简洁&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.onDelete.bind&lt;/span&gt; &lt;span class="no"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;Delete&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;利用 pattern matching + for ... by 实现 ruby 中的 each_slice 或者 lodash 的 chunk 的效果&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;tr&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;td&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;tr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 child component 要和 parent 共享 state, 那么应该由 parent 控制 state, 而 child 只需要接受 props, 控制 state 的方法可以由 props 传入&lt;/p&gt;

&lt;p&gt;假设有 Page, 有内部状态 &lt;code&gt;items&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Component&lt;/span&gt;
  &lt;span class="na"&gt;getInitialState&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

  &lt;span class="na"&gt;deleteItem&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;state.items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;setState&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;

  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;state.items.length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Items&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;state.items&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onDelete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;deleteItem&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用 Coffee 可以这样实现 Items (&lt;code&gt;func.bind(null, ...)&lt;/code&gt; 不改变 &lt;code&gt;this&lt;/code&gt; ):&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Items&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Component&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.onDelete.bind&lt;/span&gt; &lt;span class="no"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.items&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者用 &lt;code&gt;Array.map&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Items&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Component&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.items.map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.onDelete&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者用 do 语法...&lt;/p&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Items&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Component&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.onDelete&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;in&lt;/span&gt; &lt;span class="vi"&gt;@&lt;/span&gt;&lt;span class="na"&gt;props.items&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luikore</author>
      <pubDate>Sat, 07 Nov 2015 09:34:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/27985</link>
      <guid>https://ruby-china.org/topics/27985</guid>
    </item>
    <item>
      <title>纯 C 的 http web server</title>
      <description>&lt;p&gt;今天看到的 &lt;a href="https://kore.io/" rel="nofollow" target="_blank"&gt;https://kore.io/&lt;/a&gt; , 基本满足所有需要：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS 支持&lt;/li&gt;
&lt;li&gt;SPDY 支持&lt;/li&gt;
&lt;li&gt;pgsql 支持&lt;/li&gt;
&lt;li&gt;websocket 支持&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;架构类似 nginx: fork 多个进程，每进程用系统的 event&lt;/p&gt;

&lt;p&gt;自建高效率消息推送的又一个选择&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Sun, 17 May 2015 13:42:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/25609</link>
      <guid>https://ruby-china.org/topics/25609</guid>
    </item>
    <item>
      <title>Egison: 非线性模式匹配的 Lisp 方言</title>
      <description>&lt;p&gt;感谢 &lt;a href="/clongbupt" class="user-mention" title="@clongbupt"&gt;&lt;i&gt;@&lt;/i&gt;clongbupt&lt;/a&gt; 介绍，认识了 &lt;a href="www.egison.org" title=""&gt;Egison&lt;/a&gt; (号称新编程范式，东大还开了一门 Egison 的课...)&lt;/p&gt;

&lt;p&gt;关于 egison 里的一些符号：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{}&lt;/code&gt; 是 list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[]&lt;/code&gt; 是 tuple&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; 是 pattern macro&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$x&lt;/code&gt; 是声明 match variable &lt;code&gt;x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;,x&lt;/code&gt; 是引用 match variable &lt;code&gt;x&lt;/code&gt; 的值&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;说明下首页那个列举孪生素数的例子：&lt;/p&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;match-all&lt;/span&gt; &lt;span class="nv"&gt;primes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt; &lt;span class="nc"&gt;integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;[&amp;lt;join&lt;/span&gt; &lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;cons&lt;/span&gt; &lt;span class="nv"&gt;$p&lt;/span&gt; &lt;span class="nv"&gt;&amp;lt;cons&lt;/span&gt; &lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;_&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nv"&gt;[p&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;primes 是个所有素数的无穷列表，由于 Egison 偷懒用 Haskell 实现，支持无穷列表没什么障碍... 看看它的前 10 项&lt;/p&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="nv"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;;=&amp;gt; {2 3 5 7 11 13 17 19 23 29}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段 &lt;code&gt;match-all&lt;/code&gt; 代码把素数列表转换成 List Integer 作为匹配的输入，穷举所有符合 &lt;code&gt;&amp;lt;join _ &amp;lt;cons $p &amp;lt;cons ,(+ p 2) _&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; 的 &lt;code&gt;p&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cons&lt;/code&gt; 和 &lt;code&gt;join&lt;/code&gt; (我觉得叫 &lt;code&gt;concat&lt;/code&gt; 好一点...) 是构造 list 的基本函数 (ruby 的 &lt;code&gt;each_cons&lt;/code&gt; 的 &lt;code&gt;cons&lt;/code&gt; 也是来源于 lisp):&lt;/p&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cons&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cons&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cons&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="nv"&gt;{}&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="c1"&gt;;=&amp;gt; {1 2 3}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用在 pattern 中是解析构 list 的作用。另外&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_&lt;/code&gt; 是个哑元，匹配任何东西&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$p&lt;/code&gt; 将任意匹配结果赋值给 match variable &lt;code&gt;p&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;,(+ p 2)&lt;/code&gt; 求值 &lt;code&gt;p + 2&lt;/code&gt; 然后匹配 (注意前面那个逗号... 写模式语言的语法不容易...)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最后对每个匹配 &lt;code&gt;p&lt;/code&gt; 输出 &lt;code&gt;[p (+ p 2)]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;翻译成 ruby 就是&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Prime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_cons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;

&lt;p&gt;&lt;code&gt;match-all&lt;/code&gt; 是这个模式匹配的核心，基本语法是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;match-all-expr ::= '(' match-all tgt-expr matcher-expr match-clause ')'
match-clause ::= '[' pattern expr ']'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;基本 matcher 有：list, set, multiset (现在 set matcher 还有 bug 的样子，不能去重), array (未实现)
模式构造器有：cons, join, snoc (逆序的 cons...), nioj (逆序的 join)
模式运算：&lt;code&gt;|&lt;/code&gt; (或),  &lt;code&gt;&amp;amp;&lt;/code&gt; (与), &lt;code&gt;^&lt;/code&gt; (非)&lt;/p&gt;

&lt;p&gt;matcher + pattern 就决定了它是如何生成序列来搜索的，有多少个 match variable 就套多少层，一个 1000 大小的 list 用 20 个 match variable 说不定就爆炸了...&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;我觉得像极了个 prolog... 不过写法更像代码执行的顺序，而且不是 prolog 那样显式指定 sequence, 可以自定义 matcher, match variable 遵循 lexical scoping. 对比代码：&lt;/p&gt;

&lt;p&gt;Prolog 版
&lt;a href="https://gist.github.com/GRGSIBERIA/c61e05f3fbb4332bf81e" rel="nofollow" target="_blank"&gt;https://gist.github.com/GRGSIBERIA/c61e05f3fbb4332bf81e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Egison 版 (并列出所有武斗魔法少女霹雳 Q 娃系列的主角)
&lt;a href="https://gist.github.com/egisatoshi/97453be10d37287bec9c" rel="nofollow" target="_blank"&gt;https://gist.github.com/egisatoshi/97453be10d37287bec9c&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;现在还有了一个 ruby gem, &lt;a href="https://github.com/egison/egison-ruby" rel="nofollow" target="_blank"&gt;https://github.com/egison/egison-ruby&lt;/a&gt; 写法和 egison 略有不同&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Thu, 05 Feb 2015 10:20:09 +0800</pubDate>
      <link>https://ruby-china.org/topics/24127</link>
      <guid>https://ruby-china.org/topics/24127</guid>
    </item>
    <item>
      <title>静态语言元编程哪家强: Nim</title>
      <description>&lt;p&gt;Nim (原来叫 Nimrod) 是一个缩进语法，编译到 C++/ObjC/JS 的静态语言，而且：&lt;/p&gt;
&lt;h2 id="有卫生宏, 可以让用户添加新语法例如 list comprehension"&gt;有卫生宏，可以让用户添加新语法例如 list comprehension&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/def-/nim-unsorted/blob/master/listcomprehensions.nim" rel="nofollow" target="_blank"&gt;https://github.com/def-/nim-unsorted/blob/master/listcomprehensions.nim&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="可以自己插入编译规则"&gt;可以自己插入编译规则&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://nim-lang.org/trmacros.html" rel="nofollow" target="_blank"&gt;http://nim-lang.org/trmacros.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;模式语言改写 AST 超简单！比 Java 的 annotation processing tool 好一万倍&lt;/p&gt;
&lt;h2 id="const 支持编译期计算, 不需要难用得一 B 的 C++ 模板了"&gt;const 支持编译期计算，不需要难用得一 B 的 C++ 模板了&lt;/h2&gt;
&lt;p&gt;早就该这么做了...&lt;/p&gt;
&lt;h2 id="特别的标识符等价规则: 首字符大小写敏感, 其余字符不管下划线和大小写"&gt;特别的标识符等价规则：首字符大小写敏感，其余字符不管下划线和大小写&lt;/h2&gt;
&lt;p&gt;例如 &lt;code&gt;fooBar_BAZ&lt;/code&gt; 等价于 &lt;code&gt;foo_barbaz&lt;/code&gt;, 但不等价于 &lt;code&gt;FooBar_BAZ&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;作用：不管你用的库是驼峰党还是蛇党写的，自己的代码依然可以维持统一的风格...&lt;/p&gt;
&lt;h2 id="call unification: foo.bar() 相当于 bar(foo)"&gt;call unification: &lt;code&gt;foo.bar()&lt;/code&gt; 相当于 &lt;code&gt;bar(foo)&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;C++ 也要加这个 feature 啦&lt;/p&gt;
&lt;h2 id="directive guided syntax"&gt;directive guided syntax&lt;/h2&gt;
&lt;p&gt;语法可以微调，例如 &lt;code&gt;#! strongSpaces&lt;/code&gt; 可以启用 strong spaces 特性，提高无空格的操作符的结合度&lt;/p&gt;
&lt;h2 id="pragma 调整程序的行为"&gt;pragma 调整程序的行为&lt;/h2&gt;
&lt;p&gt;例如加入 NaN 和 Infinity 检查&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{.NanChecks: on, InfChecks: on.}&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="GC 可以控制步进时间"&gt;GC 可以控制步进时间&lt;/h2&gt;
&lt;p&gt;(还没看实现，难道是 G1GC?)&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;现在尝鲜很简单，到 &lt;a href="http://nim-lang.org/download.html" rel="nofollow" target="_blank"&gt;http://nim-lang.org/download.html&lt;/a&gt; 下载一个 zip 包，./build.sh 就好了&lt;/p&gt;

&lt;p&gt;hello world:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"hello".echo
echo("nim~~")
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/nim &lt;span class="nt"&gt;-r&lt;/span&gt; c hello.nim
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;

&lt;p&gt;参考这两篇博客&lt;/p&gt;

&lt;p&gt;&lt;a href="http://hookrace.net/blog/what-is-special-about-nim/" rel="nofollow" target="_blank"&gt;http://hookrace.net/blog/what-is-special-about-nim/&lt;/a&gt;
&lt;a href="http://hookrace.net/blog/what-makes-nim-practical/" rel="nofollow" target="_blank"&gt;http://hookrace.net/blog/what-makes-nim-practical/&lt;/a&gt;&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Sat, 24 Jan 2015 00:11:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/23915</link>
      <guid>https://ruby-china.org/topics/23915</guid>
    </item>
    <item>
      <title>Ruby 2.2 Tips: max (n), max_by (n), min (n), min_by (n)</title>
      <description>&lt;p&gt;经常有这样的代码&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以这么写：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min_by&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:date&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其实现不需要全排序和额外分配一个中间数组，速度往往更快&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Sat, 27 Dec 2014 16:54:39 +0800</pubDate>
      <link>https://ruby-china.org/topics/23432</link>
      <guid>https://ruby-china.org/topics/23432</guid>
    </item>
    <item>
      <title>为什么 React 这么牛</title>
      <description>&lt;p&gt;React 没有很多其他前端框架的问题：手动指定计算属性的数据依赖以确保更新，批量数据变动导致重绘卡顿，无限滚动越滚越卡，到处都是 &lt;code&gt;$scope.$apply()&lt;/code&gt; 或者 &lt;code&gt;$q.defer()&lt;/code&gt;... Atom 用了 React 以后速度快了一大截。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jlongster.com/Removing-User-Interface-Complexity,-or-Why-React-is-Awesome" rel="nofollow" target="_blank"&gt;http://jlongster.com/Removing-User-Interface-Complexity,-or-Why-React-is-Awesome&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这篇长文解释了为何，还扯到 immutable data structure 和 FRP, 还有让手机网页速度可以媲美原生应用的 &lt;code&gt;RequestAnimationFrame&lt;/code&gt;, functional lenses, immediate mode vs retained mode, 各种杂七杂八 Om, Mori, Cortext, 看完绝对会转投 React 阵营...&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Tue, 21 Oct 2014 11:28:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/22156</link>
      <guid>https://ruby-china.org/topics/22156</guid>
    </item>
    <item>
      <title>小贴士: 面条头发惊讶脸运算符</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/14b5712b8a065fa6975be7b61e55cfb6.png" title="" alt=""&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sort_by&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:-@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中秋快乐&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Mon, 08 Sep 2014 14:31:52 +0800</pubDate>
      <link>https://ruby-china.org/topics/21423</link>
      <guid>https://ruby-china.org/topics/21423</guid>
    </item>
    <item>
      <title>杭州滨江转租</title>
      <description>&lt;p&gt;最近为了各种原因以及 rubyconfchina 参会便利，要去北京住了，现在杭州住的地方想转租出去...&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.douban.com/group/topic/61779504/" rel="nofollow" target="_blank"&gt;http://www.douban.com/group/topic/61779504/&lt;/a&gt;&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Fri, 05 Sep 2014 15:07:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/21400</link>
      <guid>https://ruby-china.org/topics/21400</guid>
    </item>
    <item>
      <title>Swift 和 Ruby 差别还是挺大的...</title>
      <description>&lt;p&gt;这里讲的不是语法层面，而是运行时层面&lt;/p&gt;
&lt;h2 id="区别一: Swift 是支持泛型的静态类型"&gt;区别一：Swift 是支持泛型的静态类型&lt;/h2&gt;
&lt;p&gt;类型系统上应该说不支持泛型的 OC 和 Ruby 还比较接近，Swift 区别就有点大了。&lt;/p&gt;

&lt;p&gt;比方说数组类型，Swift 中 &lt;code&gt;[1, 2, 3]&lt;/code&gt; 的类型是 &lt;code&gt;Int[]&lt;/code&gt;, &lt;code&gt;["foo", "bar"]&lt;/code&gt; 的类型是 &lt;code&gt;String[]&lt;/code&gt;, Ruby 的数组在 Swift 中大概相当于 &lt;code&gt;Any[]&lt;/code&gt; 或者 &lt;code&gt;var x = [] // 数组类型变成了 NSArray&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;由于泛型数组的类型在编译时已经确定，所以可以比多态类型的数组更能发掘性能潜力，RC4 的 Swift 实现比 OC 实现速度快的原因就在于此。&lt;/p&gt;

&lt;p&gt;泛型约束可以极度增加函数签名的长度...&lt;/p&gt;
&lt;h2 id="区别二: nil 对象"&gt;区别二：nil 对象&lt;/h2&gt;
&lt;p&gt;Swift 默认禁止 &lt;code&gt;nil&lt;/code&gt; Object, 只有在类型上加问号 (Optional type) 才可以成为 nil.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var s: String = nil // 错误
var b: String? = nil
b?.isEmpty // nil 值链传递
b!               // 取出了 nil 值
b.isEmpty  // 错误, 你必须用 ! 拆箱或者用 ?. 去做链式调用
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="区别三: 对象系统"&gt;区别三：对象系统&lt;/h2&gt;
&lt;p&gt;Swift 是面向类的语言，对象成员表是编译时决定的。&lt;/p&gt;

&lt;p&gt;Swift 和 Ruby 同样是 单继承，和 Ruby 可以 include 任意多个 module 相比，Swift 可以添加任意多个 protocol 和 extension.&lt;/p&gt;

&lt;p&gt;构造方法 &lt;code&gt;init&lt;/code&gt; 的规则有点复杂。Swift 里可以定义两种构造方法：designated (写法是：&lt;code&gt;init(...) { ... }&lt;/code&gt;) 和 convenient (写法是 &lt;code&gt;convenient init(...) { ... }&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;convenient 构造方法的常见作用是提供某些默认值，在 convenient 构造方法中，是必须调用 designated 构造方法的。还有个限制是子类中不能调用超类的 convenient 构造方法。&lt;/p&gt;

&lt;p&gt;初始化方法的继承有两个规则：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;如果子类没有定义 designated 构造方法，那子类可以调用所有超类的 designated 构造方法。&lt;/li&gt;
&lt;li&gt;如果子类提供了与超类的所有 designated 构造方法签名相同的方法 (可以是 designated 或者 convenience 的，也可以是规则 1 继承的), 那子类可以调用所有超类的 convenience 构造方法。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;对象成员的初始化分为 2 阶段，第一阶段是放默认值 (成员声明中的 &lt;code&gt;var v = 默认值&lt;/code&gt;), 第二阶段是执行 init 方法的赋值。初始化代码中有 4 个编译时的 safety check, 如果访问顺序不满足 4 个条件，就会报错。和 Java 完全相反：Swift 是子类成员先赋值，超类成员后赋值 -- 估计这个顺序规则有利于提高性能。(从实现角度看，我猜想 Swift 对象的内存布局可能会类似下面这样，既方便实现 extension method, 又方便 init 方法的优化，没看过内存里什么样子，扯远了...)&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="n"&gt;super_klass_object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// members defined in child object&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;成员的默认值其实可以用比较复杂的代码设置，例如&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class A {
  var x = {
    ...
  }()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有些成员可以用 &lt;code&gt;@lazy&lt;/code&gt; 修饰，到用的时候才初始化 ( lazy 成员才能在初始化块中引用 &lt;code&gt;self&lt;/code&gt;)... 所以太滥用成员的初始化机制还是挺容易产生坑的... Swift 对象系统还挺复杂难掌握的... 还好报错信息都非常人性化，很容易发现问题在哪里。&lt;/p&gt;
&lt;h2 id="区别四: 传值类型和 inout"&gt;区别四：传值类型和 &lt;code&gt;inout&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;区别于 &lt;code&gt;class&lt;/code&gt;, 用 &lt;code&gt;struct&lt;/code&gt; 定义的类型都是传值类型，不用担心这类对象内存管理的问题 (下面会提到).&lt;/p&gt;

&lt;p&gt;Swift 还有一种参数属性是 &lt;code&gt;inout&lt;/code&gt;, 使得函数中可以改变参数的值。不过可以返回 tuple 了我觉得挺多余的，这到底是为了提高性能还是吸引 C# 程序员？&lt;/p&gt;
&lt;h2 id="区别五: 内存管理"&gt;区别五：内存管理&lt;/h2&gt;
&lt;p&gt;Swift 的运行时和 OC 的运行时有很大的重合，它也是基于自动引用计数而不是 GC 的，所以还是要和 OC 一样，用 &lt;code&gt;weak var&lt;/code&gt; 来避免循环引用内存不能释放的问题。如果要把 closure 中的强引用改成弱引用，就要用和 C++1x 相似的方括号语法和 &lt;code&gt;unowned&lt;/code&gt; 关键字指定 capture list, 例如&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;someClosure = {
  [unowned foo] (foo: Foo) -&amp;gt; Bar in
  ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="区别六: Immutable 对象"&gt;区别六：Immutable 对象&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;let&lt;/code&gt; 声明的变量往往会让人想起 Ruby 中的常量，但用 &lt;code&gt;let&lt;/code&gt; 对象不但不可以改变值，还不可以改变它的内部状态&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let x: Int[] = []
x.append(3)  // can not modify immutable

var x: Int[] = []
x.append(3) // ok
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="容易坑的地方"&gt;容易坑的地方&lt;/h2&gt;
&lt;p&gt;下面代码可以看到 a 和 b 指向的是同一个数组：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = [1]
b = a
a[0] = 3
b[0] // 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但是当数组长度发生变化时，就坑爹了...&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a = [1]
b = a
a.append(2)
a[0] = 3
b[0] // 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以数组是个 copy on extension 的东西，用的时候要多加注意... 用意为何没弄明白，难道是并发环境下数组内存重分配的考虑？还在在学 golang 的 slice?? 预测将来要么这个行为会改掉，要么向用户解释十几年...&lt;/p&gt;

&lt;p&gt;反射除了 &lt;code&gt;object is Klass&lt;/code&gt; 和 &lt;code&gt;reflect(object)&lt;/code&gt; 以外，都用的 objc 的反射机制，所以还得回想 objc 的 selector ...&lt;/p&gt;

&lt;p&gt;如果想获得 class 对象，需要自己包装一个调用 &lt;code&gt;[object class]&lt;/code&gt; 的函数暴露给 swift&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"".respondsToSelector("respondsToSelector:") // true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;少数函数如 &lt;code&gt;CGColorGetRandomColor&lt;/code&gt; 返回对象是没有被 ARC managed 的，需要手动 retain 和 release, 参见 &lt;code&gt;Unmanaged&lt;/code&gt; 的文档 ...&lt;/p&gt;
&lt;h2 id="和 OC / C 交互"&gt;和 OC / C 交互&lt;/h2&gt;
&lt;p&gt;Swift 比引入 Ruby Framework 的优点之一是语言内建了方便交互的桥梁。&lt;/p&gt;

&lt;p&gt;在 Swift 项目中加个 &lt;code&gt;.m&lt;/code&gt; 文件或者在 OC 项目中加个 &lt;code&gt;.swift&lt;/code&gt; 文件，XCode 就会问你要不要加个 &lt;code&gt;项目名-Bridging-Header.h&lt;/code&gt;, 然后你把相应的头文件加进去就可以在 Swift 中使用了。&lt;/p&gt;

&lt;p&gt;例如 OC 用 &lt;code&gt;NS_ENUM&lt;/code&gt; 定义的枚举类型在 Swift 中就可以直接用：&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="nf"&gt;NS_ENUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSInteger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyEnum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BAR&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;swift:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var e: MyEnum = MyEnum.BAR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没用 &lt;code&gt;NE_ENUM&lt;/code&gt; 定义，也能用，只是相当于整数类型了。不过好处是范围依然有检查：&lt;/p&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BAR&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;MyEnum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;swift:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var e: MyEnum = 2
e = 3 // 错误, 超出范围了
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="简化的 CF API"&gt;简化的 CF API&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swift 数组有定型 native 形式和 NSArray 形式，当用 native 形式时，可以直接赋值给 CFArrayRef 而不用像 OC 那样 &lt;code&gt;__bridge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;create ... release 的内容，在 swift 里都可以省掉 release 了&lt;/li&gt;
&lt;li&gt;CFMake* 都映射成了短很多的结构体构造函数，并且是带命名参数的&lt;/li&gt;
&lt;li&gt;有很多很长前缀的枚举类型，在 Swift 中都直接可以 . + 后缀使用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;例如 &lt;a href="https://www.youtube.com/watch?v=-vXMF4_uwdQ" rel="nofollow" target="_blank" title=""&gt;Swift Interoperability In Depth&lt;/a&gt; 中提到的：&lt;/p&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;drawGradientRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;startColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;endColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;colorSpace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGColorSpaceCreateDeviceRGB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// 不用手动 CGColorSpaceRelease 了&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;gradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGGradientCreateWithColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colorSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;startColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endColor&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;// 不用 __bridge&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;startPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 代替 Make 系列函数&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;endPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;CGContextDrawLinearGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="特色 feature"&gt;特色 feature&lt;/h2&gt;
&lt;p&gt;整数类型 Int 在 64 位系统相当于 Int64, 在 32 位系统相当 Int32.&lt;/p&gt;

&lt;p&gt;为了解决溢出问题，Swift 的运算符默认检查溢出，但是前面加了 &lt;code&gt;&amp;amp;&lt;/code&gt; 的话就不检查 (例如 &lt;code&gt;&amp;amp;+&lt;/code&gt;, &lt;code&gt;&amp;amp;*&lt;/code&gt;, &lt;code&gt;&amp;amp;%&lt;/code&gt; ...).&lt;/p&gt;

&lt;p&gt;Swift 还可以声明 &lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;||=&lt;/code&gt; 等赋值操作符，估计将来可以写原子性的检查 - 赋值语句，但是貌似还不支持 objc 中的 &lt;code&gt;@synchronized&lt;/code&gt;, &lt;code&gt;@atomic&lt;/code&gt; 等 attributes.&lt;/p&gt;

&lt;p&gt;playground 只能用系统已经提供的库，暂时还不能引入项目中内容或者第三方库&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Wed, 04 Jun 2014 18:07:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/19735</link>
      <guid>https://ruby-china.org/topics/19735</guid>
    </item>
    <item>
      <title>[你还不用 pg?] 坑爹的 MySQL 事务</title>
      <description>&lt;p&gt;mysql 的事务隔离级别 repeatable read 并不能阻止常见的并发更新。&lt;/p&gt;

&lt;p&gt;下面代码中 c 和 c2 就是两个并发的 session, c2 在事务中给字段 &lt;code&gt;accounts.money&lt;/code&gt; 做了 +1 操作，但 c 在 c2 的事务进行了一半时修改了 &lt;code&gt;accounts.money&lt;/code&gt; 的值，结果就是没发生任何事务错误，把 c 的更新给丢了，用户神秘损失 1 块钱。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"mysql2"&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mysql2&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:host&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:username&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'use dummy'&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'set autocommit=1'&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'delete from accounts'&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'insert into accounts (money) values (1)'&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"at first money = 1"&lt;/span&gt;

&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'select * from accounts'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mysql2&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:host&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:username&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'use dummy'&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'set autocommit=1'&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'set transaction isolation level repeatable read'&lt;/span&gt;

  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'start transaction'&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c2 starts transaction"&lt;/span&gt;

  &lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"select * from accounts where id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'money'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c2 selected money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# to let c change money&lt;/span&gt;

  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s2"&gt;"update accounts set money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; where id=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c2 set money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s1"&gt;'commit'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# to let c2 select money&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c set money = 2"&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt; &lt;span class="s2"&gt;"update accounts set money = 2 where id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意这个是 mysql 的问题，上面的代码写成 sql 存储过程也一样存在。解决的方法只有读数据时改成 &lt;code&gt;select ... for lock in share mode&lt;/code&gt;, 或者直接改用 pg:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"pg"&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PGconn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt; &lt;span class="ss"&gt;dbname: &lt;/span&gt;&lt;span class="s1"&gt;'dummy'&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"set autocommit to on"&lt;/span&gt; &lt;span class="c1"&gt;# NOTE, if off, it will require transaction wrapping single statement updates&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;'delete from accounts'&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"at first money = 1"&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;'insert into accounts (money) values (1)'&lt;/span&gt;
&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'select * from accounts'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PGconn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt; &lt;span class="ss"&gt;dbname: &lt;/span&gt;&lt;span class="s1"&gt;'dummy'&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"set autocommit to on"&lt;/span&gt;

  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;'start transaction isolation level repeatable read'&lt;/span&gt;
  &lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"select * from accounts where id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'money'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c2 selected money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"update accounts set money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; where id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c2 set money = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;money&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;'commit'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"c set money = 2"&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"update accounts set money = 2 where id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;

&lt;p&gt;5-24 更正：一开始我的理解不对，确切的说是 mysql repeatable read 隔离等级的问题而与 phantom read 无关，为免误解已经把幻读部分去掉。&lt;/p&gt;

&lt;p&gt;mysql 的 repeatable read 真的会禁止 phantom read, 也就是事务内两次查询得到的 id 集合是一致并且正确的，但是记录的内容不保证正确。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mysql 的解决办法是对读到的记录加锁，或者用 read committed + 乐观锁也可以。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/Tony612" class="user-mention" title="@Tony612"&gt;&lt;i&gt;@&lt;/i&gt;Tony612&lt;/a&gt; &lt;a href="/saiga" class="user-mention" title="@saiga"&gt;&lt;i&gt;@&lt;/i&gt;saiga&lt;/a&gt; &lt;a href="/bhuztez" class="user-mention" title="@bhuztez"&gt;&lt;i&gt;@&lt;/i&gt;bhuztez&lt;/a&gt;  晚上做了实验，发现 mysql 用 repeatable read + 乐观锁依然可以防止错误的并发更新。原因是 rails 的乐观锁使用了这样的更新语句：&lt;code&gt;where id = ? and lock_version = ?&lt;/code&gt;, 如果别的事务更新 &lt;code&gt;lock_version&lt;/code&gt;, 这个查询得到的记录集合就是空的，就 phantom read 了，而 mysql 对 phantom read 的处理是正确的，然后就会产生事务错误，防止了并发更新的数据丢失。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;以下代码，mysql 可以在默认的隔离等级中识别乐观锁&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"active_record"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"mysql2"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"logger"&lt;/span&gt;

&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DEBUG&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;
  &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;establish_connection&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
    &lt;span class="ss"&gt;adapter: &lt;/span&gt;&lt;span class="s1"&gt;'mysql2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;database: &lt;/span&gt;&lt;span class="s1"&gt;'dummy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s1"&gt;'root'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;pool: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;
  &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_all&lt;/span&gt;
  &lt;span class="n"&gt;ar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="n"&gt;ar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;ar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# columns: id serial, n integer, lock_version integer&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;fork&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;connect&lt;/span&gt;
  &lt;span class="n"&gt;init&lt;/span&gt;
  &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"t1: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"t1 updated"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;fork&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;connect&lt;/span&gt;
  &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
  &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"t2: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"t2 updated"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'-'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;n&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luikore</author>
      <pubDate>Fri, 23 May 2014 17:49:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/19499</link>
      <guid>https://ruby-china.org/topics/19499</guid>
    </item>
    <item>
      <title>关于算法, 我们该学什么?</title>
      <description>&lt;p&gt;如果给你一个改进算法的任务，你是盲头苍蝇的 google 又 google 试了又试，还是利用算法知识一下找到问题所在？以我浅薄的经验，觉得应该学的是这些：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;寄存器，内存，硬盘，IO 操作速度的不同之处&lt;/li&gt;
&lt;li&gt;时间/空间复杂度，大 O 记法，多项式复杂度的基本概念&lt;/li&gt;
&lt;li&gt;单/多递归函数的时间/空间复杂度&lt;/li&gt;
&lt;li&gt;工作语言中的常用操作的复杂度 (例如 &lt;code&gt;array.index?&lt;/code&gt; 的最佳和最差情况)&lt;/li&gt;
&lt;li&gt;二分和排序等常见的 log(n) 或者 n log(n) 的算法 (进阶：&lt;a href="http://en.wikipedia.org/wiki/L_notation" rel="nofollow" target="_blank" title=""&gt;大 L 记法&lt;/a&gt;, 其他复杂度类别).&lt;/li&gt;
&lt;li&gt;给一个简单问题知道该用/搜什么算法或者 API 去解决 (这是经验), 不知道算法名称但能直接写代码搞定其实更好 (这是能力)...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;如果要求底层算法：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;文件 IO 和 mmap&lt;/li&gt;
&lt;li&gt;几种基本&lt;a href="http://www.memorymanagement.org/glossary/" rel="nofollow" target="_blank" title=""&gt;内存管理&lt;/a&gt;的实现 (malloc, memory pool, arena, reference counting, trace GC 等)&lt;/li&gt;
&lt;li&gt;CPU 架构：高级缓存，page fault, cache miss, cache line, cache oblivion 等概念和应用&lt;/li&gt;
&lt;li&gt;CPU 架构：流水线，分支预测，超向量指令等概念和应用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;如果关心计算并行化：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;task parallel 和 data parallel 的基本概念&lt;/li&gt;
&lt;li&gt;差分方程和母函数法的应用&lt;/li&gt;
&lt;li&gt;把简单的算术运算转换成矩阵运算&lt;/li&gt;
&lt;li&gt;认出可以优化成 c 倍快或者 log(c) 倍快的代码模式 (其中 c 是核的数目)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;如果是数据分析，暂时只想到这些：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;用 &lt;a href="http://en.wikipedia.org/wiki/Probably_approximately_correct_learning" rel="nofollow" target="_blank" title=""&gt;PAC learning&lt;/a&gt; 评价选择适合业务的算法 (关于这个数学框架 Tom Mitchell 的 Machine Learning 有详述)&lt;/li&gt;
&lt;li&gt;反向传播算法 (在神经网络，SGD, 各种数值系统都有广泛应用) 和 viterbi 算法 (在 RCG 语法解析，隐马尔可夫模型，条件随机场，和电子方面都有广泛应用)&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>luikore</author>
      <pubDate>Sun, 12 Jan 2014 22:57:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/16750</link>
      <guid>https://ruby-china.org/topics/16750</guid>
    </item>
    <item>
      <title>Postgres 的 CTE 好像很不错</title>
      <description>&lt;p&gt;CTE = common table expressions 类似于 AR 的 scope&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.craigkerstiens.com/2013/11/18/best-postgres-feature-youre-not-using/" rel="nofollow" target="_blank"&gt;http://www.craigkerstiens.com/2013/11/18/best-postgres-feature-youre-not-using/&lt;/a&gt;
&lt;a href="http://ruby-china.org/topics/9333?page=1#reply14" rel="nofollow" target="_blank"&gt;http://ruby-china.org/topics/9333?page=1#reply14&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;设想：在这个基础上做个偷懒的 ORM 的话，大概可以比 ActiveRecord 快不少...&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Thu, 09 Jan 2014 02:17:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/16703</link>
      <guid>https://ruby-china.org/topics/16703</guid>
    </item>
    <item>
      <title>[姨妈] 终于把 rvm 换成 rbenv 了</title>
      <description>&lt;p&gt;后知后觉...&lt;/p&gt;

&lt;p&gt;主要是 rvm 几点不太爽：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gemset 和 bundler 功能重复&lt;/li&gt;
&lt;li&gt;autolib 太傻瓜&lt;/li&gt;
&lt;li&gt;rubygems-bundler 自作聪明&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;rbenv 就没这些问题。&lt;code&gt;brew install rbenv ruby-build rbenv-gem-rehash&lt;/code&gt; 改改启动脚本就好了，弄起来还挺简单的，重新安装 ruby 速度也飞快&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CONFIGURE_OPTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--with-readline-dir=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt; readline&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; rbenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; 2.1.0-dev
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luikore</author>
      <pubDate>Sun, 08 Dec 2013 21:25:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/16073</link>
      <guid>https://ruby-china.org/topics/16073</guid>
    </item>
    <item>
      <title>ctags 替代物: ripper-tags</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/tmm1/ripper-tags" rel="nofollow" target="_blank"&gt;https://github.com/tmm1/ripper-tags&lt;/a&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="n"&gt;ins&lt;/span&gt; &lt;span class="n"&gt;ripper&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;
&lt;span class="n"&gt;ripper&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>luikore</author>
      <pubDate>Sun, 08 Dec 2013 13:48:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/16061</link>
      <guid>https://ruby-china.org/topics/16061</guid>
    </item>
    <item>
      <title>CSS 解决 field error 的重复代码</title>
      <description>&lt;p&gt;表单验证 error 字段写起来是挺麻烦的事情，最后生成的 html 会像是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;label&amp;gt;
  &amp;lt;input&amp;gt;
  &amp;lt;!-- 下面这个还是条件出现的 --&amp;gt;
  &amp;lt;div class="field-error"&amp;gt;...&amp;lt;/div&amp;gt;
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前人发明了各种各样的 form builder 和 helper 去简化这种页面结构的创建... 搞得页面很复杂而且前端不友好&lt;/p&gt;

&lt;p&gt;但这种小问题用 css 就能简单搞定... 假设页面这么写&lt;/p&gt;
&lt;pre class="highlight slim"&gt;&lt;code&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;data-error&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;[field]
  &lt;span class="nt"&gt;input&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;样式这么写&lt;/p&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-error&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data-error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;data-error&lt;/code&gt; 属性的内容就会自动附加到后面。效果见 &lt;a href="http://codepen.io/anon/pen/LCzGA" rel="nofollow" target="_blank"&gt;http://codepen.io/anon/pen/LCzGA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;混合前端验证的话，直接改 &lt;code&gt;data-error&lt;/code&gt; 属性就好了。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data-hint&lt;/code&gt; 等同理&lt;/p&gt;

&lt;p&gt;你还用 simple_form?&lt;/p&gt;</description>
      <author>luikore</author>
      <pubDate>Sat, 23 Nov 2013 15:25:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/15744</link>
      <guid>https://ruby-china.org/topics/15744</guid>
    </item>
  </channel>
</rss>
