代码中的空白区域

谢益辉 2017-01-28

友情提示:密集恐惧症患者请跳过本文。

程序里经常会用到选择分支语句,if-else 之类的。一旦条件分支变多,程序结构可能会变成这样一团毛线球(假设写一个分段函数吧):

f = function(x) {
  if (x < 0) {
    x = -x
  } else if (x >= 0) {
    if (x < 3) {
      x = x^2
    } else {
      x = exp(x)
    }
  }
  x
}

我一般不太喜欢左侧空白区域太大的代码,选择分支太多也会让我昏头。我倾向于写紧凑的代码,原因只有一个:显示器只有辣么小(悲伤却辣么大)。我希望在我的眼球转动和鼠标滚动单位距离里能看尽量多的代码(看完代码就可以看《颈椎康复指南》了),如果空白区域太多,我需要更大的眼球扫描距离,以及更大的脑缓存来存放我的脑内存读入信息。如果客官们看过我的程序代码的话,应该会经常看见我提早用 return(),这就是为了避免接下来又要缩进一层。上面的函数如果我来写,我一般会写成这个德性:

f = function(x) {
  if (x < 0) return(-x)
  if (x < 3) return(x^2)
  exp(x)
}

提前 return() 可以避免下文的 else 分支,也可以避免继续缩进。除了这些外观上的因素,更重要的是,每往后读一段代码,都可以放心,当前的分支情况是上一个 return() 的条件的补集,比如写 x < 3 的时候实际上蕴含着 0 <= x < 3 了。当然这样的写法有个坏处,就是代码前后依赖,你不能随意移动代码,比如把第二个分支直接剪切到第一个分支之前。我自己通常不会这样移动代码,但有时候也需要调整分支的前后位置,这个情况就是:如果下一个分支对应的代码(显著)比上一个分支短的话,我会先写短的这个分支。例:

f = function(x) {
  if (x < 0) {
    z = rnorm(1, x)
    return(z/100)
  }
  rcauchy(1, x)
}

第一个分支下有两行代码,第二个分支只有一行。那么我会把第二个分支换作第一个:

f = function(x) {
  if (x >= 0) return(rcauchy(1, x))
  z = rnorm(1, x)
  z/100
}

前一种写法左侧有14个空格,后一种写法只有6个空格。

最后一种减少大面积左侧空白区域的办法是一个名字很长的函数小括号后直接换行,而不是在参数逗号后换行。逗号后换行是更常见的写法,如:

shiny::updateSelectizeInput(session, "foo", label = "New Label",
                            selected = c("A", "B"), choices = LETTERS,
                            server = TRUE)

这种世事苍茫成云烟的写法给我带来的虚无感会让我联想到虚无与大地之外的悲怆,而我自己会用这种写法:

shiny::updateSelectizeInput(
  session, "foo", label = "New Label", selected = c("A", "B"),
  choices = LETTERS, server = TRUE
)

用多出来的一行回括号换取左侧更小的空白区域。