在Ruby中,如何打开包含类对象的变量?

时间:2017-04-03 13:47:51

标签: ruby semantics least-astonishment flawed-concept

如果我写这个:

case v
when String
  puts :String
else
  puts :other
end

如果我将v设置为"some string",我会收到'字符串'。

如果我将v设置为String,我会得到'其他'。

我应该怎样'切换'包含多个类对象之一的变量?

这是如何尊重'最少惊喜'的成熟计算原理的?

请不要告诉我修补“班级”课程。

4 个答案:

答案 0 :(得分:3)

我同意===case使用的测试)可能令人困惑。

它通常被称为“案例相等运算符”,但===既不是reflexive nor symmetric nor transitive,所以它根本不像是一个相等的行为:

String === "test"
# true
"test" === String
# false
String === String
# false
String === Class
# false
Class === String
# true
Class === Class
# true

我读过a === b的最佳说明来自@JörgWMittag的answer

如果我有一个标有a标签的抽屉,将b放入抽屉是否合理?

对于你的问题,你可以写:

v = String
case v
when Class
  puts "#{v} is a Class, let's investigate some more"
  # another case, if statements or hash lookup...
else
  puts :other
end

答案 1 :(得分:1)

  

我应该怎样'切换'包含多个类对象之一的变量?

使用Module#<=

case v
when String then "instance of string"
when ->(c) { c <= String } then "class derived from String"
end
  

这是如何尊重'最少惊喜'的成熟计算原理的?

完美。

答案 2 :(得分:1)

您可以在没有对象的情况下使用case

case 
when v == String
  puts 'v is String class'
when v.is_a?(String)
  puts 'v is an instance of String'
else
  puts 'v is something else'
end

这类似于if - elsif - else表达式。

答案 3 :(得分:1)

ruby​​和其他一些函数式语言中的case表达式与命令式switch语句cousins完全不同。

正如其他人所提到的,case表达式使用===方法,这是一种模式定义方法。在a === b范例中,a是一种描述可能实例集合的模式。 b是一个可能适合该模式/集合的实例。将a === b视为:

  

做'a'描述'b'?

  

'a'包含'b'?

一旦理解了这一点,String === String #=> false并不令人惊讶,因为StringClass的一个实例,因此它符合Class模式。

case表达式和switch语句之间的另一个独特区别是case表达式只是:表达式。这意味着你可以做这样的酷事:

puts case v.name
  when "String"
    :String
  else
    :other
  end if v.is_a? Class

此代码仅在v为类时执行,然后根据类的名称启用v.nameputs

由于ruby作为鸭子类型语言的本质,在变量中有一个类并且需要打开它是极其罕见的。如果你感到沮丧case并不像你希望的那样优雅,请给我们更多关于你的目标的背景信息,我们也许能够提出一个优雅的解决方案,避免一起切换。