我有一个这样的函数:
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_i
(value.to_f
)的方法,否则返回nil
。方法to_integer
和to_float
很有用,因为它们会告诉您字符串是否可以转换为给定的数字类型,如果可以,还会给您数值。
在考虑如何实现to_integer
和to_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'