21个Ruby面试必备问题 *

最好的Ruby开发人员和工程师可以回答的全部基本问题. 在我们社区的推动下,我们鼓励专家提交问题并提供反馈.

现在就聘请一名顶级Ruby开发人员
Toptal logo是顶级自由软件开发人员的专属网络吗, designers, finance experts, 产品经理, 和世界上的项目经理. 顶级公司雇佣Toptal自由职业者来完成他们最重要的项目.

面试问题

1.

打电话和打电话有什么区别 super and calling super()?

View answer

A call to super 使用传递给子方法的相同参数调用父方法. 因此,如果传递给子方法的参数与父方法的期望不匹配,就会发生错误.

A call to super() 如预期的那样,不带任何参数调用父方法. 一如既往,在代码中显式是一件好事.

(Thanks to Ruby Gotchas 对于这个问题.)

2.

What will val1 and val2 在执行下面的代码后等于? 解释你的答案.

提示:该语句在IRB中的输出为NOT value of val1!
val2 = true && false
View answer

虽然这两个表述看起来是等价的, they are not, 由于操作的顺序. 具体来说, and and or operators have lower 优先于 = 算子,而 && and || operators have higher 优先于 = 运算符,基于运算顺序.

为了澄清这一点, 下面是相同的代码, 但是使用括号来澄清操作的默认顺序:

(val1 = true)和false #导致val1等于true
val2 = (true && False) #导致val2等于False

This is, incidentally, 这是一个很好的例子,说明为什么使用括号来清楚地说明你的意图通常是一个很好的做法, in any language. 不管你是否用括号, 重要的是要了解这些操作顺序规则,从而确保正确地确定何时使用 and / or vs. && / ||.

3.

下面列出的哪个表达式会导致 "false"?

true    ? "true": "false"
false   ? "true": "false"
nil     ? "true": "false"
1       ? "true": "false"
0       ? "true": "false"
"false" ? "true": "false"
""      ? "true": "false"
[]      ? "true": "false"
View answer

In Ruby, the only 计算结果为false的值是 false and nil. Everything else -即使是零(0)和空数组([])-计算结果为true.

对于以前使用JavaScript等其他语言的程序员来说,这是一个真正的惊喜.

(Thanks to Ruby Gotchas 对于这个问题.)

申请加入Toptal的发展网络

并享受可靠、稳定、远程 自由Ruby开发人员职位

申请成为自由职业者
4.

编写一个函数,按照字符串形式的键的长度对散列中的键进行排序. 例如,哈希值:

{ abc: 'hello', 'another_key' => 123, 4567 => 'third' }

应导致:

["abc", "4567", "another_key"]
View answer

在编程中总是如此,实际上有多种方法可以实现这一点.

最直接的答案是:

hsh.keys.map(&:to_s).sort_by(&:length)

or:

hsh.keys.collect(&:to_s).Sort_by {|key| key.length }

另外,Ruby的 Enumerable mixin 提供许多操作集合的方法. 这里的关键是将散列键转换为一个集合, 将它们全部转换为字符串, 然后对数组进行排序.

Def key_sort HSH
	hsh.keys.collect(&:to_s).sort { |a, b| a.length <=> b.length }
end

的等效调用 collect method 是用通常的块语法完成的:

收集{|x| x.to_s }
5.

考虑以下两种方法:

def times_two (__arg1);
  puts arg1 * 2;
end

Def sum(arg1, arg2);
  将arg1 + arg2;
end

下面每一行代码的结果是什么?

times_two 5
times_two(5)
times_two (5)
sum 1, 2
sum(1, 2)
sum (1, 2)
View answer

如预期的那样,前三行代码都将打印出10.

接下来的两行代码都将如预期的那样打印出3.

然而,最后一行代码(i.e., sum (1,2))将导致以下结果:

语法错误,unexpected ',', expected ')'
sum (1, 2)
       ^

问题在于方法名和左括号之间的空格. 由于空间的原因,Ruby解析器认为 (1, 2) 是表示单个参数的表达式,但是 (1, 2) 不是一个有效的Ruby表达式,因此错误.

注意,单参数方法不会出现这个问题(如我们的 timesTwo 方法),因为只有一个值 is 一个有效的表达式(例如.g., (5) 是一个有效表达式,其计算结果为5).

6.

考虑下面的代码:

VAL = 'Global'
 
module Foo
  VAL = 'Foo Local'
 
  class Bar
    def value1
      VAL
    end
  end
end
 
class Foo::Bar
  def value2
    VAL
  end
end

下列各项的价值是什么?

Foo::Bar.new.value1
Foo::Bar.new.value2

解释你的答案.

View answer

Foo::Bar.new.value1 将等于 'Foo Local' and Foo::Bar.new.value2 将等于 'Global'.

Here’s why:

The module 关键字(以及 class and def 关键词)将创建一个新的 lexical scope 所有的内容. 以上模块 Foo 因此创建了作用域 Foo in which the VAL 常数等于 'Foo Local' is defined. Inside Foo,我们声明类 Bar,它创建另一个新的词法作用域(名为 Foo::Bar),它也可以访问它的父作用域(i.e., Foo)和它的所有常数.

然而,当我们声明 Foo::Bar (i.e., using ::),我们实际上还在创造 another 词法范围,也就是 also named Foo::Bar (这怎么会让人困惑呢!). 然而,这个词法作用域没有父(i.e.,它完全独立于词汇范围 Foo ),因此无法访问' Foo '作用域的内容. 因此,在课堂内部 Foo::Bar,我们只能进入 VAL 在脚本开头声明的常量.e.(在任何模块之外) 'Global'.

7.

下面的代码行是有效的Ruby代码吗? 如果有,它有什么作用? 解释你的答案.

-> (a) {p a}["Hello world"]
View answer

Yes, it’s valid. 以下是如何理解它的作用:

The -> 操作符创建一个新的Proc,它是Ruby的函数类型之一. (The -> 通常被称为“刺杀过程”. 它也被称为“stabby lambda”,因为它创建了一个新的Proc实例,它是一个lambda. 所有的函数都是过程,但不是所有的过程都是函数. 两者之间有一些细微的差别.)

这个特定的进程接受一个参数(即, a). 当调用Proc时,Ruby执行该块 p a,这相当于 puts(a.inspect) (一个微妙但有用的区别,这就是为什么 p 有时比 puts for debugging). 因此,这个进程只是打印传递给它的字符串.

方法调用Proc call method on Proc, 或者使用方括号语法, 所以这行代码也调用了Proc并将字符串" Hello World "传递给它.

所以把所有这些放在一起,这行代码(a)创建了一个接受单个参数的Proc a 然后(b)调用该进程并向它传递字符串" Hello world ". 所以,简而言之,这行代码输出“Hello World”.

8.

解释以下每一项 operators 以及如何以及何时使用它们: ==, ===, eql?, equal?.

View answer

== – Checks if the value 的两个操作数相等(通常重写以提供特定于类的相等定义).

=== -专门用于测试平等内部 when clause of a case 语句(也经常被重写以在case语句中提供有意义的特定于类的语义).

eql? – Checks if the value and type 的两个操作数是相同的(与 == 比较值但忽略类型的操作符). For example, 1 == 1.0 evaluates to true, whereas 1.eql?(1.0) evaluates to false.

equal? – Compares the identity of two objects; i.e., returns true 如果两个操作数具有相同的对象id (i.e.,如果它们都指向 same object). 注意,这将返回 false 当比较两个相同的 copies 同一个物体.

(Thanks to Ruby Gotchas 对于这个问题.)

9.

Given:

x = "hello"

解释两者的区别:

x += " world"

and

x.concat " world"
View answer

The += 操作符用新值重新初始化变量,因此 a += b 等于 a = a + b.

因此,尽管它可能 seem that += 它在改变这个值,实际上是在创建一个 new 对象,并将旧变量指向新对象.

这样写可能更容易理解:

foo = "foo"
foo2 = foo
foo.concat "bar"

puts foo
=> "foobar"
puts foo2
=> "foobar"

foo += "baz"
puts foo
=> "foobarbaz"
puts foo2
=> "foobar"

(Examining the object_id of foo and foo2 还会演示正在创建的新对象吗.)

这种差异对表现有影响,也有不同于预期的突变行为.

10.

在Ruby代码中,您经常会看到使用如下表达式的技巧 array.map(&:method_name) 的简写形式 array.映射{|element| element.method_name }. 它究竟是如何工作的?

View answer

参数传递时 & 在它前面(表明它将被用作块),Ruby将调用 to_proc 试图使它作为一个块可用. Symbol#to_proc 很方便地返回a Proc 它将调用传递给它的任何内容的对应名称的方法, 这样我们的速记技巧就能起作用了.

11.

编写一行Ruby代码,将任意长度的斐波那契数列打印为数组.

(Hint: use inject/reduce)

View answer

有多种方法可以做到这一点,但一个可能的答案是:

(1..20).inject( [0, 1] ) { | fib | fib << fib.last(2).inject(:+) }

当你沿着序列往上走 fib, you sum, or inject(:+),取数组中的最后两个元素,并将结果添加到末尾 fib.

Note: inject is an alias of reduce

12.

你能在Ruby类的外部使用它的对象调用一个私有方法吗?

View answer

是的,在 send method.

Given the class Test:

class Test
   private
       def method
         p“我是一个私人方法”
      end
end

我们可以使用 send:

>> Test.new.send(:method)
“我是一个私人方法”
13.

考虑下面的代码:

class A
  def self.a(b)
    if b > 0
      b * b
    end
  end
end

以下的值是什么:

  • var1 = A.a(0)
  • var2 = A.a(2)
View answer
  • Var1等于 nil
  • Var2等于 4

Understand: Ruby中的条件语句是一个返回的表达式 nil 如果条件是 false. Ruby方法返回方法体中的最后一个表达式.

在这个例子中:

  • A.a(0) returns nil 不成功的条件
  • A.a(2) 返回的平方 2, i.e 4
14.

两者的区别是什么 Array#map and Array#each?

Note: collect is an alias of map

View answer
  • Array#each 方法迭代数组的元素并每次执行所提供的块. 但是,它不受影响地返回原始数组.
  • Array#map 将返回一个新的元素数组,其中包含由它提供的块返回的值. 它也不会影响原始数组

Example:

# Given
>> arr = [1,2,3,4]

#这将打印2,4,6,8,但将返回[1,2,3,4]
>> arr.each {|x| puts x*2; x*2 }
2
4
6
8
=> [1, 2, 3, 4]


#这也将打印2,4,6,8,但返回[2,4,6,8]
>> arr.map {|x| puts x*2; x*2 }
2
4
6
8
=> [2, 4, 6, 8]
15.

如何移除? nil 数组中的值使用ruby?

View answer

Array#compact removes nil values.

Example:

>> [nil,123,nil,"test"].compact
=> [123, "test"]
16.

For the class ABC the given as:

class ABC
  def xyz
    把“xyz放入ABC”
  end
end

返回值是什么:

  • ABC::new::xyz
  • ABC::new.xyz
  • ABC.new::xyz
  • ABC.new.xyz
View answer

通过对象调用xyz方法的所有语句都是有效的.

当我们穿过 IRB:

irb(main):001:0> ABC::new::xyz
xyz in ABC
=> nil
irb(main):002:0> ABC::new.xyz
xyz in ABC
=> nil
irb(main):003:0> ABC.new::xyz
xyz in ABC
=> nil
irb(main):004:0> ABC.new.xyz
xyz in ABC
=> nil
17.

这个变量的值是多少 upcased 在下面的代码段中?

upcase = ["one", "two", "three"].Map {|n|放n.upcase }

View answer

大写= [nil, nil, nil]

让我们一起来看看 puts as below:

>> puts "Hi"
Hi
=> nil

Note the nil 最后,这是返回值 puts. After all, puts is a method,所以它必须返回一些东西. 当它发生时,它总是返回 nil. 打印出字符串是该方法执行的操作.

Similarly, 评估问题中的代码,我们可以理解,虽然期望结果是一个常见的学习者错误 [“一”,“二”,“三”]. In fact, it’s [nil, nil, nil]. 的返回值 puts to be nil.

18.

假设运行了以下代码:

if false
  foo = 'test'
end

价值是什么?

  • defined? foo
  • defined? bar
View answer
defined? foo
#=> "local-variable"
defined? bar
#=> nil

foo 至少已被解释器读取,因此定义并赋值为 nil value. However, since bar 从来没有被写出来,从来没有被定义过.

19.

的区别是什么 Object methods clone and dup?

View answer

Object#dup 创建对象的浅拷贝. 例如,它不会复制任何混合模块方法,而 Object#clone will. 这可以通过下面的代码示例来显示:

class Klass
  attr_accessor: str
end

module Foo
  def foo; 'foo'; end
end

s1 = Klass.new #=> #
s1.extend(Foo) #=> #
s1.foo #=> "foo"

s2 = s1.clone #=> #
s2.foo #=> "foo"

s3 = s1.dup #=> #
s3.foo #=> NoMethodError: undefined method `foo' for #
20.

两者的区别是什么 extend and include in ruby?

View answer
  • include 将指定的模块方法混合为目标类中的实例方法
  • extend 将指定的模块方法混合为目标类中的类方法

给定以下类定义:

模块ReusableModule
  def module_method
    放置“模块方法:你好! 我是一个模块方法"
  end
end

类ClassThatIncludes
  包括ReusableModule
end
类ClassThatExtends
  延长ReusableModule
end

Here’s how ClassThatIncludes behaves:

类方法不存在
>> ClassThatIncludes.module_method
ClassThatIncludes:Class的未定义方法' module_method'

存在有效的实例方法
>> ClassThatIncludes.new.module_method
模块方法:你好! 我是一个模块方法
=> nil

Here’s how ClassThatExtends behaves:

存在有效的类方法
>> ClassThatExtends.module_method
模块方法:你好! 我是一个模块方法
=> nil

实例方法不存在
ClassThatExtends.new.module_method
NoMethodError: undefined method `module_method' for #

我们应该提一下 object.延长ExampleModule makes ExampleModule 方法在对象中作为单例方法可用.

21.

Ruby中使用了多少类型的变量,它们是什么?

View answer

Ruby中有4种类型的变量:

  1. 类变量以 @@, e.g. @@my_var
  2. 实例变量以 @, e.g. @my_var
  3. 全局变量以 $, e.g. $my_var
  4. 局部变量没有前缀,但方法参数和块参数以 _, e.g. _my_arg (实际上,前缀为 _ 被像RuboCop这样的程序认为是无用的变量吗, 你不关心它的值是多少)

面试不仅仅是棘手的技术问题, 所以这些只是作为一个指南. 并不是每一个值得雇佣的“A”候选人都能回答所有的问题, 回答所有问题也不能保证成为A级考生. 一天结束的时候, 招聘仍然是一门艺术,一门科学,需要大量的工作.

Why Toptal

厌倦了面试候选人? 不知道该问什么才能让你得到一份好工作?

让Toptal为你找到最合适的人.

现在就聘请一名顶级Ruby开发人员

我们的独家Ruby开发者网络

希望找到一份Ruby开发人员的工作?

让Toptal为你找到合适的工作.

申请成为Ruby开发人员

工作机会从我们的网络

提出面试问题

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

*所有字段均为必填项

寻找Ruby开发人员?

Looking for Ruby Developers? 查看Toptal的Ruby开发人员.

Clemens Helm

自由Ruby开发人员

AustriaToptal Member Since 2017年10月24日

克莱门斯作为一名全栈web开发人员已经工作了超过15年. 他热衷于设计和制造高质量的产品. 他最喜欢的自由职业是有机会遇到各种类型的项目, people, and cultures. 以这种方式工作,他不断获得经验和知识,为他的下一个项目.

Show More

Duarte戴安娜

自由Ruby开发人员

PortugalToptal Member Since 2017年1月19日

Duarte是一名高级开发人员,拥有十多年构建web应用程序的经验, 使用rails和react. 他管理过工程团队,但仍然热爱编程. 无论是从头开始构建产品还是整合现有的团队, 他从第一天起就会很有效率.

Show More

Bruno Costa

自由Ruby开发人员

PortugalToptal Member Since 2019年11月4日

Bruno是一名全栈开发人员,拥有工程背景和对产品方面的巨大热情. 在创业环境中工作, 他积累了丰富的经验,身居多个职位,几乎成功地扮演了每一个角色. 布鲁诺目前的工作是在网站Exercism上指导Ruby课程.io. 描述布鲁诺时,我脑海中浮现的一些词是自信、无情和乐观.

Show More

Toptal连接 Top 3% 世界各地的自由职业人才.

加入Toptal社区.

Learn more