无法在ruby中使用eval执行Class(参数)



我有一个这样的函数:

def check_if_correct_type(type, value)
    # nil.test!
    # eval(type.classify(value)) rescue return false
    # true
    case type
    when "integer"
        !!Integer(value) rescue return false
    when "float"
        !!Float(value) rescue return false
    else
        return true
    end
    true
end

一个样本将是

 check_if_correct_type("integer", "a")

我试着改变这样的功能:

check_if_correct_type(type, value)
  !!(eval(type.classify(value))) rescue return false
  true
end

这是抛出错误。我该如何解决这个问题。我对元编程还很陌生,所以有点迷失了方向。


更新1:

"adfadf".kind_of?(String) #=> true
123.kind_of?(String)      #=> false
# The "Fixnum" class is actually used for integers
"adfadf".kind_of?(Fixnum) #=> false
123123.kind_of?(Fixnum)   #=> true 
12.3.kind_of?(Float)      #=> true
"sadf".kind_of?(Float)    #=> false
12.kind_of?(Float)        #=> false

以上内容对我来说不起作用吗?函数会找到对象的类型,对我来说,答案要求如下:

check_if_correct_type("integer", "1221") #=> true
check_if_correct_type("float", "1.24") #=> true
check_if_correct_type("string", "asds12") #=> true
check_if_correct_type("float", "asdasd1.24") #=> false

其中作为

"1.24".kind_of?(浮动)#=>错误

这就是为什么转换对我有效。希望问题现在更清楚了。


更新2:

如果我使用公共发送,这就是我得到的。

public_send("integer".capital("1"))ArgumentError:参数数量错误(0为1)来自(撬):4:在capitalize' [5] pry(main)> !!public_send("integer".classify("1")) ArgumentError: wrong number of arguments (1 for 0) from /home/aravind/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/core_ext/string/inflections.rb:187:in中分类""

注意:classification是RubyonRails的一部分,而不是Ruby。

我建议您按照以下方式编写方法:

def correct_type?(type, str)
  case type.downcase
  when "integer"
    !!to_integer(str)
  when "float"
    !!to_float(str)
  else
    raise ArgumentError, "type must be 'integer' or 'float'"
  end
end

其中,如果value是整数(浮点)的字符串表示,则to_integer(value)to_float(value))是返回value.to_ivalue.to_f)的方法,否则返回nil。方法to_integerto_float很有用,因为它们会告诉您字符串是否可以转换为给定的数字类型,如果可以,还会给您数值。

在考虑如何实现to_integerto_float之前,我想对correct_type?的必要性提出疑问。而不是:

str = "33"
if correct_type?("integer", str)
  n = str.to_i
  puts n
else
  ...
end

写不是更好吗

if (n = to_integer("33"))
  puts n
else
  ...
end

方法CCD_ 13和CCD_。第一种是你采取的方法:

def to_integer(str)
  raise ArgumentError unless str.is_a? String
  s = str.gsub(/s/,'')
  Integer(s) rescue nil
end
def to_float(str)
  raise ArgumentError unless str.is_a? String
  s = str.gsub(/s/,'')
  return nil if to_integer(s)
  Float(s) rescue nil
end
to_integer("3")     #=> 3 
to_integer("-3")    #=> -3 
to_integer("+  3")  #=> 3 
to_integer("cat")   #=> nil 
to_integer("3.14")  #=> nil 
to_integer(:cat)    #=> ArgumentError: ArgumentError
to_float("3.14")    #=> 3.14 
to_float("-3.14")   #=> -3.14 
to_float("+  3.14") #=> 3.14 
to_float("cat")     #=> nil 
to_float("3")       #=> nil 
to_float(:cat)      #=> ArgumentError: ArgumentError

第二种方法是使用正则表达式:

def to_integer(str)
  raise ArgumentError unless str.is_a? String
  s = str.gsub(/s/,'')
  s[/^[+-]?s*d+$/] ? s.to_i : nil
end
def to_float(str)
  raise ArgumentError unless str.is_a? String
  s = str.gsub(/s/,'')
  return nil if to_integer(s)
  s[/^[+-]?s*d+.d+$/] ? s.to_f : nil
end
to_integer("3")     #=> 3 
to_integer("-3")    #=> -3 
to_integer("+  3")  #=> 3 
to_integer("cat")   #=> nil 
to_integer("3.14")  #=> nil 
to_integer(:cat)    #=> ArgumentError: ArgumentError
to_float("3.14")    #=> 3.14 
to_float("-3.14")   #=> -3.14 
to_float("+  3.14") #=> 3.14 
to_float("cat")     #=> nil 
to_float("3")       #=> nil 
to_float(:cat)      #=> ArgumentError: ArgumentError

不需要使用eval来发送消息。您只需使用send即可:

def check_if_correct_type(type, value)
  !!send(type.capitalize, value) rescue return false
  true
end

注意:在Ruby核心库或Ruby标准库中的任何地方都没有名为classify的方法。还要注意的是,盲目地捕捉所有的异常是一个非常糟糕的主意。

我不认为在这个例子中使用元编程有什么意义。你应该避免在不需要的地方使用它。一般来说,你的程序的逻辑应该是:

a) 检查输入值的类型。b) 将类型与作为参数输入的类型进行比较。或代码:

def check_if_correct_type(type, value)
  actual_type = value.class.name
  return actual_type.downcase == type.downcase
end
p check_if_correct_type('string', 'test') #=> true
p check_if_correct_type('integer', 'test2') #=> false

这可以在一行中缩短,但在两行中这样做是为了更清楚地展示正在发生的事情

如果您想检查对象的类,正确的方法是:

"adfadf".kind_of?(String) #=> true
123.kind_of?(String)      #=> false
# The "Fixnum" class is actually used for integers
"adfadf".kind_of?(Fixnum) #=> false
123123.kind_of?(Fixnum)   #=> true 
12.3.kind_of?(Float)      #=> true
"sadf".kind_of?(Float)    #=> false
12.kind_of?(Float)        #=> false

没有理由使用Integer()Float()方法来检查类型。这些是类型转换方法,它们将把其他类型转换为Float或Fixnum。如果您确实想尝试将类型转换为Float或numeric,这是一种方法,但可能还有更好的方法。

一般来说,您不应该计划将引发和挽救异常作为普通程序流程的一部分;其中一个原因是它非常慢。异常应用于错误和异常/异常情况,而不是经常出现异常的常规情况。

绝对不要开始把eval纳入其中,天哪,你为什么要这么做?

这就是我最终解决问题的方法

def check_if_correct_type(type, value)
    !!eval("#{type.classify}(value)") rescue return false
    true
end

此函数的示例输出如下,以防您想知道它是否为

[25] pry(main)> value = "1"
=> "1"
[26] pry(main)> !!eval("#{type.classify}(value)")
=> true
[27] pry(main)> value = "a"
=> "a"
[28] pry(main)> !!eval("#{type.classify}(value)")
ArgumentError: invalid value for Float(): "a"
from (pry):28:in `eval'
[29] pry(main)> value = "1.4"
=> "1.4"
[30] pry(main)> type = "integer"
=> "integer"
[31] pry(main)> !!eval("#{type.classify}(value)")
ArgumentError: invalid value for Integer(): "1.4"
from (pry):31:in `eval'

最新更新