【问题标题】:Rewrite method using case in Ruby在 Ruby 中使用 case 重写方法
【发布时间】:2014-11-05 23:53:53
【问题描述】:

所以我在module 中定义了这个class File,我想做的是重写self.parse 方法,以便它使用case。我是Ruby 的新手,所以这对我来说并不简单。此外,该方法的主体中包含的代码行数不得超过8。任何想法如何做到这一点?我也在Code Review 上问过,他们说这对他们来说是题外话。


module RBFS
    class File
        attr_accessor :content
        def initialize (data = nil)
            @content = data
        end

        def data_type
            case @content
                when NilClass then :nil
                when String then :string
                when TrueClass , FalseClass then :boolean
                when Float , Integer then :number 
                when Symbol then :symbol                                                              
            end
        end

       def serialize
           case @content
               when NilClass then "nil:"
               when String then "string:#{@content}"
               when TrueClass , FalseClass then "boolean:#{@content}"
               when Symbol then "symbol:#{@content}"
               when Integer , Float then "number:#{@content}"        
           end
       end

       def self.parse (str)
           arr = str.partition(':')
           if arr[0] == "nil" then return File.new(nil) end
           if arr[0] == "string" then return File.new(arr[2].to_s) end
           if (arr[0] == "boolean" && arr[2].to_s == 'true') then return File.new(true) end
           if (arr[0] == "boolean" && arr[2].to_s == 'false') then return File.new(false) end
           if arr[0] == "symbol" then return File.new(arr[2].to_sym) end
           return File.new(arr[2].to_i) if (arr[0] == "number" && arr[2].to_s.include?('.') == false)
           return File.new(arr[2].to_f) if (arr[0] == "number" && arr[2].to_s.include?('.') == true)
       end
   end
end

'RBFS::File.parse' 的工作原理示例:

RBFS::File.parse("string:"Hello world") => #<RBFS::File:0x1c45098 @content="Hello world"> #Tested in irb

【问题讨论】:

    标签: ruby if-statement case


    【解决方案1】:

    我个人更喜欢这个:

    def self.parse(arg)
      key, value = arg.to_s.split(':')
      {
        'nil'     => new(nil), 
        'string'  => new(value),
        'boolean' => new(value == 'true'),
        'symbol'  => new(value.to_sym),
        'number'  => new(value.include?('.') ? BigDecimal(value) : Integer(value))
      }[key]
    end
    

    上面的代码实际上是 2 行,为了便于阅读,分成多行。但是,如果必须使用 case,那么您可以将代码更改为:

    def self.parse(arg)
      key, value = arg.to_s.split(':')
      case key
      when 'nil' then new(nil)
      when 'string' then new(value)
      when 'boolean' then new(value == 'true')
      when 'symbol' then new(value.to_sym)
      when 'number' then new(value.include?('.') ? BigDecimal(value) : Integer(value))
      end
    end
    

    【讨论】:

    • 您对将最后一个case 更改为new(case key; when 'nil' then nil; when 'string then value...end)arg = case key; when 'nil' then nil;....end; new(arg) 有何看法?
    • 我也想过这样做,但是看起来不太好,所以我没有写它,你认为把它也提一下是个好主意吗? :)
    • @CarySwoveland:两个原因 - 1) BigDecimal 在货币计算方面比 Float 可靠得多。 2) BigDecimal 可以轻松更改为 float(to_f) 但不能反过来。
    • 对不起,Surya,BigNum 在大脑上。删除了我之前的评论,也将删除这条评论...
    【解决方案2】:

    在 Ruby 中,case 语句使用 case equality method #=== 进行测试。除了您已经在#serialize#data_type 中实现的类型检查之外,#=== 对几种不同的比较返回 true。例如:

    Integer === 1    //=> true
    Numeric === 1    //=> true
    (1..10) === 1    //=> true
    1 === 1          //=> true
    

    有了这些知识,我们可以构造一个#parse 方法,如下所示:

    def parse(serialized)
      type, content = serialized.split(':') # A neat trick that'll make things more readable.
      case type
      when 'nil'
         # ...
      when 'string'
         # ...
      when 'boolean'
         # ...
      when 'symbol'
         # ...
      when 'number'
         # ...
      else
        raise "Invalid RBFS file."
      end
    end
    

    我不确定您是否能够在不影响文件的可读性或删除我在末尾添加的错误处理步骤(我强烈推荐)的情况下在 8 行中执行此操作,但要接近,您可以使用when ... then ... 语法。

    【讨论】:

      【解决方案3】:

      以下是您可以编写此内容的一种方式的建议。当然,它未经测试。我做了两个假设:

      • 你所说的a[2]是一个字符串,所以a[2].to_s是不必要的。
      • 如果a[0] =&gt; "boolean"a[2]'true''false'
      module RBFS
        class File
          attr_accessor :content
          def initialize (data = nil)
            @content = data
          end
      
          def data_type
            class_to_sym[@content.class]
          end
      
          def serialize
            return nil if @content.class == NilClass
            "#{class_to_sym[@content.class].to_s}:#{@content}"
          end
      
          def self.parse (str)
            type,_,val = str.partition(':')
            File.new(type_to_arg(type, val))
          end
      
          private
      
          def class_to_sym
             { NilClass=>:nil, String=>:string, TrueClass=>:boolean,
               FalseClass=>:boolean, Numeric=>:number, Symbol=>:symbol }
          end
      
          def type_to_arg(type, val)
            case type
              when "nil"     then nil
              when "string"  then val
              when "boolean" then val == 'true' 
              when "symbol"  then val.to_sym 
              when "numeric" then val[/\./] ? val.to_f : val.to_i 
              end
            end
          end
      
        end
      end
      

      如果您愿意,可以将val[/\./] 替换为val.include?('.')

      您也可以使用散列来模拟 type_to_arg 中的 case 语句:

      def type_to_arg(type, val)
        { "nil"    =>nil,
          "string" =>val,
          "boolean"=>(val=='true'),
          "symbol" =>val.to_sym,
          "number" =>val[/\./] ? val.to_f : val.to_i
        }[type]
      end
      

      【讨论】:

      • 你到底是什么意思:注意99.class =&gt; Fixnum,而不是Integer
      • 看来我又搞砸了,但谢谢。我只用Float=&gt;:number 替换了我的哈希Class_to_Sym 中的Fixnum=&gt;:number, Float=&gt;:number。那应该可以。正确的?让我知道您发现的任何其他问题。
      • 我觉得不错。只是一件事,也许它更像是一种编码风格偏好,所以如果你不喜欢这个想法,我会说忽略它。我猜Class_to_Sym 可以是私有方法而不是常量,原因是常量将被初始化并占用内存,而方法将初始化该哈希直到其范围。此外,可以在代码中更改常量,而不能更改方法。我记得在一个答案中,您已将计算代码移至方法,所以我想为什么不将 case type .. 移至类方法然后调用:File.new(determine_type type )
      • @Suyra。感谢您的建议。我已经实施了这两个建议。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-27
      • 2012-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多