4

我偶然发现了 Ruby 的 Ruby 习语||=(),如:

def app_logger
  @app_logger ||= (
    logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
    logfile.sync = true
    AppLogger.new(logfile)
  )
end

我尝试使用{}而不是(),但它没有用。我认为{}是为了封闭一个块。

这是一个众所周知的成语吗?是不是很好的风格?

我还没有找到很多关于这种使用括号的文档。任何指针都会有所帮助。

请注意这篇文章是关于()这种方式的使用,而不是||=. 已经有很多关于后一个成语的帖子。

4

3 回答 3

6

就像 Ruby 中可以做的很多事情一样,很多事情应该做,这就是其中之一。

当已经有其他设施时使用括号对代码进行分组可能会造成混淆,并且几乎可以肯定与许多编码风格指南相反。如果我在我正在管理的代码中看到这一点,我会立即修复它。

最好是使用begin/end标记来完全清楚发生了什么:

def app_logger
  @app_logger ||= begin
    logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
    logfile.sync = true
    AppLogger.new(logfile)
  end
end

Ruby 中的很多东西都被评估为一个单一的值,而其中的内容(...)显然就是其中之一。

您另一个foo ||= (a=10; a+10)“更好”的例子也颇具争议。这做了两个赋值和加法,但只是有条件的。这个几乎总是最好用长格式写成begin/end以清楚地表明这a+10是结果。

从风格的角度来看,隐藏“重要”部分,a+10行尾的 , 是不好的,可以忽略。将其作为最后一行使其非常清晰。这也是为什么if在长行末尾添加语句也不好的原因,它隐藏了该行仅有条件地执行。

对简洁性的关注总是比对可读性的关注更重要。在磁盘上保存几个字节对你一点帮助都没有,因为有人误读了你的代码,他们引入了一个严重的错误。

当你被自己的聪明所吸引时,将来有人可能是你。我们所有人都曾在某个时候发生过。

于 2013-05-01T15:07:16.163 回答
2

除了@tadman 的回答,我认为以更类似于 Ruby 的方式编写该方法可以保持可读性并保持良好和紧凑:

def app_logger
  return @app_logger if @app_logger

  logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
  logfile.sync = true
  @app_logger = AppLogger.new(logfile)
end

对于我以这种方式编写它的意图和理由,请参阅我对这个答案的评论以回应@fotanus 的评论。

当我们学习编程和学习新语言时,我们的大脑会习惯于观察模式。无论模式是由调试器发出的十六进制代码还是 C、Perl、Python、Java 或 Ruby,我们仍然可以看到模式。当我们习惯于看到它们时,我们倾向于将代码更改为类似于那些熟悉的结构。这就是为什么 Perl 和 C 程序员一开始倾向于像 C 和 Perl 一样编写 Java、Python 和 Ruby。“美在旁观者的眼中”,但当它不合适时,同样的美是一棵杂草,就像野花在正式的花园或球道中间不合适一样。我们应该用编程语言的方言来写作,因为那是生活在这片土地上的人们所期望的说话方式。

需要记住的是,尽管我们个人可能是一个研究代码的怪物,可以将代码从多行缩减为单个字符,但让我继续工作的是编写其他人可以理解的代码的能力,但不一定必须具有相同的口径。代码处理总是在它被缩减到最小尺寸之前达到收益递减点,特别是当代码在生产环境中运行并且由初级程序员维护并且需要扩展或调试它时,以及时钟在滴答作响。Minutes = dollars在我工作的地方,美元的乘数非常大,当虫子炸弹爆炸时,这会导致墙壁像蟑螂一样泄漏管理人员。(哦……我有没有把经理称为蟑螂?随便。)

在事件发生后的第二天早上被叫来并感谢他们编写的代码,使他们可以轻松地调试/修复或修改/扩展,这比在凌晨 2:45 被叫并被要求上网寻求帮助要好得多。我重视我的睡眠和我的编码伙伴的睡眠,并将可维护的代码作为我们的第一要务。

那是我的 0.02 美元。

于 2013-05-01T15:45:44.593 回答
0

在我看来,括号真的很难看。为什么不将创建记录器背后的逻辑委托给方法?

def app_logger
  @app_logger ||= instantiate_app_logger
end

def instantiate_app_logger
  logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
  logfile.sync = true
  AppLogger.new(logfile)
end

但我担心它会破坏一些 OOP,你的代码也会。为什么 AppLoger 类无法根据传递的路径打开文件并打开同步?会干净很多。

于 2013-05-01T19:39:47.927 回答