rubymine ide似乎在看到否定条件语句时发出警告。我想知道为什么使用否定条件语句是不好的?纯粹是因为可读性吗?
例如,在此代码中:

class Complement
    def self.of_dna dna_strand
      dna_array =  dna_strand.chars
      dna_complement  = ['']
      dna_structure = ['C', 'G', 'T', 'A']

      dna_array.each do |strand|
        unless dna_structure.include? strand
          return ''
        end

        case strand
        when "C"
         dna_complement << "G"
        when "G"
         dna_complement << "C"
        when "T"
         dna_complement << "A"
        when "A"
         dna_complement << "U"
        end
      end
    dna_complement.join('')
  end
end

我想知道在这种情况下unless dna_structure.include? strandif !(dna_strucutre.include?)有什么不同?

最佳答案

由于ruby不仅有if,而且还有unless,因此只要得到的代码是清晰的,就鼓励您使用它。就是说你应该转换成这样:

if (!string.empty?)
  # ...
end

变成这样:
unless (string.empty?)
  # ...
end

但也有例外,比如当你有这个的时候:
if (!string.empty?)
  # ... when not empty
else
  # ... when empty (when not not empty)
end

天真的做法是将其转换为unless,但这会产生一个三重负。您已经在处理double了,else子句只在字符串不是空的,或者可以说不包含任何内容的情况下才会发生。
请改为:
if (string.empty?)
  # ... when empty
else
  # ... when not empty
end

这里采用的方法有很多问题,但最严重的是每次调用方法时都要在方法中声明一个常量数组。因为这永远不会改变,所以它在类的顶层是一个常量。至少:
class Complement
  DNA_STRUCTURE = %w[ C G A T ]
end

更好的方法是使用映射表来表示对:
COMPLEMENT = {
  'C' => 'G',
  'G' => 'C',
  'T' => 'A',
  'A' => 'U'
}.freeze

现在看一下您试图“反转”给定字符串的特定问题,您真正需要的工具是字符串本身的tr,该方法是为处理字符之间存在1:1映射的密码之类的事情而优化的。
您的整个函数将折叠为:
def self.of_dna(strand)
  strand.tr('CGTA', 'GCAU')
end

现在,如果您想做一个快速测试,以确保您实际处理的是一个有效的序列:
def self.of_dna(strand)
  return '' unless (strand.match(/\A[CGTA]*\z/))

  strand.tr('CGTA', 'GCAU')
end

这里还有一些其他的坏习惯,比如当字符串在特定任务上做得更好时,创建数组来保存单个字符。c = ''然后c << 'G'将比相同的数组版本更有效,特别是考虑到数组将包含n个字符串,每个字符串都会带来一些开销,并且需要在末尾使用join创建另一个字符串。当使用ruby时,尽量减少计算所需的对象数量,不管是临时的还是其他的。用更少的“垃圾”通常更快。

07-26 01:35