面试题答案
一键面试容易被忽略的陷阱
- 对象的类继承关系:
- 当使用
case
语句进行类型匹配时,如果类存在继承关系,可能会出现非预期的匹配。例如:
class Animal; end class Dog < Animal; end class Cat < Animal; end pet = Dog.new case pet when Dog puts 'It is a dog' when Animal puts 'It is an animal' end
- 在这个例子中,
pet
是Dog
类的实例,Dog
类继承自Animal
类。按照case
语句的执行顺序,会先匹配到Dog
,输出It is a dog
。但如果不小心把when Animal
放在when Dog
之前,就会匹配到Animal
分支,这可能不是预期的结果。
- 当使用
===
运算符的重载:case
语句实际上是使用===
运算符进行匹配。一些类可能重载了===
运算符,其行为可能与预期不同。例如,Range
类重载了===
用于检查一个值是否在范围内:
num = 5 case num when 1..10 puts 'Number is between 1 and 10' end
- 这里
1..10
是一个Range
对象,Range
类的===
方法被重载以检查数字是否在范围内。如果不了解这种重载机制,在自定义类中重载===
时可能会导致意外的匹配结果。
nil
值的匹配:- 当匹配可能为
nil
的值时,需要特别注意。例如:
value = nil case value when String puts 'It is a string' when nil puts 'It is nil' end
- 如果
when nil
写在when String
之后,由于nil
不是String
类型,不会匹配到String
分支,但也不会匹配到nil
分支,因为case
语句一旦遇到一个匹配就会停止。所以应该把when nil
放在前面,以确保正确匹配。
- 当匹配可能为
性能优化
- 减少不必要的匹配分支:
- 只保留必要的匹配条件,避免冗余分支。例如:
num = 7 case num when 1..5 puts 'Number is between 1 and 5' when 6..10 puts 'Number is between 6 and 10' # 避免不必要的分支 # when 1..10 # puts 'Number is between 1 and 10' end
- 在这个例子中,如果已经有了具体范围的匹配分支,就不需要再写一个包含所有情况的宽泛分支,这样可以减少匹配时的计算量。
- 按可能性高低排序分支:
- 将最有可能匹配的分支放在前面。例如,在一个处理用户输入的程序中,如果大部分用户输入的是数字,就把数字匹配分支放在前面:
input = gets.chomp case input when /^\d+$/ puts 'It is a number' when /^[a-zA-Z]+$/ puts 'It is a word' else puts 'Other input' end
- 这样可以在大多数情况下更快地找到匹配分支,提高性能。
- 缓存匹配结果(对于动态数据):
- 如果
case
语句中的匹配条件是基于动态计算且计算量较大,可以考虑缓存结果。例如,假设要根据用户角色进行权限判断,而获取用户角色是一个开销较大的数据库查询:
def get_user_role(user_id) # 模拟数据库查询 sleep(1) 'admin' end user_id = 1 role = get_user_role(user_id) case role when 'admin' puts 'Full access' when 'user' puts 'Limited access' end
- 这里先获取
role
并缓存起来,而不是在case
语句每次都调用get_user_role
方法,从而提高性能。
- 如果