Ruby 一道 Ruby 水平自测题.

zw963 · 2013年04月15日 · 最后由 chenge 回复于 2016年07月04日 · 8100 次阅读

看到有位同学发帖秀 Rails 面试题。个人表示... 到目前为止,那些题目对我仍旧有压力... 正好让我也想起了之前遇到的一个 Ruby 问题。


class Class
  def to_proc
    proc {|x,y| new x, y }
  end
end

 [[1, "a"], [2, "b"], [3, "c"]].map(&Array)    # => 请使用 Ruby 1.9 以上版本, 说出你的答案.

我不妨斗胆再对您的 Ruby 水平做个论断:(随便瞎扯,仅供参考)

  1. 如果你可以不执行代码输出结果 (而且不看我下面总结的内容), 在三分钟之内写出正确的结果,并且可以理清所有细节,那么你一定很牛!能涉及到这些 (偏门的) 的 Ruby 知识,而且到达如此深度,这已经可以说明一切了。

  2. 如果你直接看代码不明所以,执行输出结果后,五分钟之内想通,也不错啦!这需要非常熟悉 Ruby 才行的。偶不记得花了几分钟了,但肯定超过 5 分钟了。不过记得那会儿老婆在旁边看电视古装剧,麻烦得很。

  3. 如果你完全看得懂代码原义, 但是完全想不通为啥是这个结果... 不要灰心,大家都是这个阶段过来的,而且你的 Ruby 水平也是靠谱的。有时间可以试着深度研究下,或者参考下底下的知识点,再或者花点时间 Google 一下,也许就懂了呢?就算不懂也其实也没关系,可以先放下,过几个月再来看。每个人都在进步嘛。

  4. 如果你看不懂全部 代码原义, 这其时也不代表什么。你对 Ruby 不太熟悉罢了。不过,做项目之余,也许你该恶补 (或系统学习一下) Ruby 的基础知识了。

  5. 好吧,也许你猜出了结果了... 即使你完全不懂 Ruby....


不谈这道题的实用性的前提下,我认为这道题很有代表性,可以很好的考验一个 Rubyist 的以下诸方面关键的能力:

  1. 如何 open_class, 打 monkey_patch.
  2. Ruby 类和类对象
  3. 什么是 Proc 对象。proc 和 lambda 有那些不同点。
  4. 什么叫闭包?如何形成闭包?闭包在这里的用处?
  5. Ruby 中 & 的隐式调用。
  6. 理解 self .

猜出来的:

[%w(a), %w(b b), %w(c c c )]

#1 楼 @ashchan 我觉得这道题最容易让人去查 API 的地方是 Array.new

哈哈,我也是,别的都看懂了,就是不知道 Array.new 传这两个参数的用法。

本来想不透,看到楼上说的我就明白了

完全看不懂

def to_proc proc {|x,y| new x, y } end 比较少见。

貌似我该补一下基础知识了?...

看不懂...

很少人会关注 new x,y 会返回什么吧? 这个测试让人蛋疼。 我觉得关键还是 &Array 相当于

if Array.is_a?(Proc)
  Array
else
  Array.to_proc
end

map { |x| Array.to_proc.call x }

第一个段看不懂。

擦,原来 Array.new 还有这种传参法

#9 楼 @gihnius

👍, 讲的真好呀~

貌似大家的关注点.... 怎么都跑到 Array.new 的参数上去了... 看来个人差异很大呀。

事实上这个例子,因为加了一个参数的缘故,貌似更加直白了,我之前看到这个例子的时候,是下面这样的。

class Class
  def to_proc
    ->(args) { new args }
  end
end

 [[1], [2], [3]].map(&Array)    # => 请使用 Ruby 1.9 以上版本, 说出你的答案.

我看了老半天, 才明白... new 的真正含义...

#13 楼 @zw963 你这个更简单了。这道题我就查了下 Array.new(3, "a") 的 API,本来以为是 [3, "a"] 没想到是 ["a", "a", "a"] 然后仔细看了一下 Array.new,看来盲点很多啊。


原来这个帖子 http://ruby-china.org/topics/5645 有这个讨论。

其实楼主这个问题很不错的,在应用中有不少人经常用这个方法来处理map中对象的转换和封装的。它可以更一般化

class Class
  def to_proc
    proc(&method(:new))
  end
end

这样就可以根据需要随意的创建对象了,只有有对应的构造方法

[{:name => 'Tom'}, {:name => 'Jerry'}].map(&User) 

或者做类型转换,

User.all.map(&UserWrapper)

#14 楼 @zgm

哈 . 可当时第一次看到这代码,唯一的盲点是:self... 有点蒙,老以为怎么那么像 Csharp 中的 new 关键字... 可能是最近 CSharp 代码看多了吧。

事实上,这个问题也的确是在我查 Csharp 中的 lambda 的用法时,在 so 看到的。

看不懂……

用这个来应试 Ruby 程序员好像用晦涩的文言文来应试新闻记者一样 - 能看出文学功底,但也仅此而已

看不懂。不如直接考元编程相关的。

我记得 Hash 也有一个点可以拿来玩,这个技巧很好使,但是用来做面试题有失偏颇

看不懂,也不知道这个面试意义多大,看的懂的可能在语言底层的细节非常扎实,说明是一个非常注重细节理解的人。可能需要的工作岗位是要求编写非常细致的代码,对性能、安全性、稳定性要求很高的岗位。

从头将大家的评论看了下,大家都很客观的~~如果是我,我是在第一时间没看出结果的。

#2 楼 @zgm 完全同意。

大概能看出来意思,结果运行一下发现不对 因为不知道 Array.new(x,y) 的意义

#15 楼 @donnior

早上就看到这个回复,因为在做事儿,扫了眼,根本没看明白。刚才有重新读了下。足足花了 20 分钟,把代码流程过了一遍,终于看明白了,而且有了不少心得体会,自觉又长进了一些。哈哈。

看来我的代码真的起到了 抛砖引玉 的作用,很明显比我的代码又复杂了不止一层呀,额外涉及到了许多知识点,对学习很有帮助,不过... 我那个够晦涩了,这个远比那个还要晦涩....

如果实际代码中,我可能会写下面的代码更直接一点

[{:name => 'Tom'}, {:name => 'Jerry'}].map {|e| User.new(e) }

另外有一个问题想请教你:

class Class
  def to_proc
    proc &method(:new)
  end
end

User.to_proc  # => #<Proc:0x00000001ab3848 (lambda)>

你明明用的是 proc &method(:new),为什么返回的却是 lambda ?

#26 楼 @zw963 method(:new).to_proc.lambda? => true

#26 楼 @zw963

proc_object = proc {p}
p proc_object.lambda?    # => false

proc_object = proc &method(:p)
p proc_object.lambda?   # => true

#26 楼 @zw963 哈哈,你还是在走学院派啊。

#27 楼 @zgm

可是方法定义是:

def to_proc
  proc &method(:new)
end

proc 应该返回 Proc 才是呀!lambda &method(:new) 返回 lambda 才对呀。

你可以试试下面的代码:

class Class
  def to_proc
    proc {}
  end
end

User.to_proc  # => 不再是 lambda 了.

#28 楼 @donnior

这正是我疑问的地方...

proc_object = proc &method(:p)
p proc_object.lambda?   # => true

为什么这个会返回 lambda ?? 难道有什么猫腻?

上面那个返回 lambda, 还要下面代码有什么用?

lambda_object = lambda &method(:p)

#29 楼 @hisea

干嘛加个还...... 我也在做项目呀!! 😄

#32 楼 @zw963 加个还,是因为你一直走学院派路线啊。哈哈

#33 楼 @hisea

虽然有点较真,但还真从没想过自己被当做学院派... 看来我自己还蛮适合搞研究,造 核爆蛋 更适合点。

@zw963

puts proc {}
puts proc &lambda{}
puts proc &method(:puts)
puts proc &proc{}
puts proc &:puts
puts "=" * 50
puts lambda {}
puts lambda &lambda{}
puts lambda &method(:puts)
puts lambda &proc{}
puts lambda &:puts
puts "=" * 50
puts Proc.new {}
puts Proc.new &lambda{}
puts Proc.new &method(:puts)
puts Proc.new &proc{}
puts Proc.new &:puts

=> 

#<Proc:[email protected]:1>
#<Proc:[email protected]:2 (lambda)>
#<Proc:0x874b078 (lambda)>
#<Proc:[email protected]:4>
#<Proc:0x874afec>
==================================================
#<Proc:[email protected]:7 (lambda)>
#<Proc:[email protected]:8 (lambda)>
#<Proc:0x874af10 (lambda)>
#<Proc:[email protected]:10>
#<Proc:0x874afec>
==================================================
#<Proc:[email protected]:13>
#<Proc:[email protected]:14 (lambda)>
#<Proc:0x874adf8 (lambda)>
#<Proc:[email protected]:16>
#<Proc:0x874afec

不同的用法只和默认的对象有关,从 behavior 来说,lambda 可以理解为匿名的 method,他们都有严格的参数个数的限制,但 proc 没有,这是 proc 的魔法。

看书的时候只看了 lambda,完全看不懂 proc,要好好学习

想了一下想出来了,然后忍不住跑了跑,居然是对得……其实这题不大懂 Ruby 蒙也蒙的对吧。虽然挺有意思,不过个人比较反感面试考核这种题目。考点公司实际碰到的问题更好。

BTW,这种方法生成的 array,每个元素都是引用同一个对象,感觉没有什么实际意义,而且算是个坑……

re = Array.new 3, 'a'
re[0].object_id == re[1].object_id     # true

唉,忘记 Array.new 还可以接收数字作为参数的用法了。

把《ruby 元编程》这本书的前五章看懂理解这个没有问题,被卡在了 Array.new(2, 'b' )

步骤化解过程

[[1, "a"], [2, "b"], [3, "c"]].map(&Array)
[[1, "a"], [2, "b"], [3, "c"]].map {|size, obj| Array.to_proc size, obj }
[[1, "a"], [2, "b"], [3, "c"]].map {|size, obj| Array.new      size, obj }
# => [["a"], ["b", "b"], ["c", "c", "c"]]

#35 楼 @donnior #36 楼 @zgm

谢谢两位!你们提供的信息,化解了我之前对于 & 的一个 很大很大的误解,哈哈。

#9 楼 @gihnius 请教,为何执行 &Array 的时候,ruby 知道去找 Class#to_proc这个方法呢?ruby怎么知道Class里面有这么一个方法能把Array转换为proc?

#44 楼 @baxiaopeng 你可以这么理解:&object 其实就是从 object 返回 Proc 的语法糖。

#44 楼 @baxiaopeng

Ruby 的确不知道。但是它会尝试调用 to_proc. 这是 Ruby 语言内建的 隐式转换机制.

#46 楼 @zw963 我想这就是【约定优于配置】吧。:D

浇盆冷水,窃以为,这种题目在面试中,如果面试者是个刚从学校出来的学生,也许有点用,否则没多少用处,针对 lz 提到的六个要点,我宁愿一个个直接拿出来问待面试者的理解,然后再展开深入的了解待面试者做过的事情,对技术的理解,对碰到问题的处理方式,和队友的相处方式,我觉得,招聘需要关注很多方面,会做题,远不表示对知识的掌握

#47 楼 @baxiaopeng 【约定优于配置】是 rails 的风格,别弄混了啊。

#48 楼 @pzgz

哈哈。其实,这道题的意义就在于:对六个要点一一分解,并吃透,并理解这些要点在这里例子中实际起到的作用。这绝不是一道给出答案就完了的题。能挖掘很多东西出来 (以上六点,又可以引申出不少东西来), 这正好可以作为你对面试者挖掘的起点,否则,你直接提出问题,而没有一个实际例子,这样很难描述以上 知识点 吧?

p.s.

好吧,其实从头到脚,我只是提了一句,看到有人贴 Rails面试题, 然后我想到之前遇到的一个问题, 而且我标题也说了么... 是自测题~ 是楼上的各位 XD 硬要把这道题作为面试题。

#49 楼 @zgm 对呀,这是 Ruby 语言内建的约定, 貌似没有 配置 呀。

#50 楼 @zw963

嗯,有可能是我太敏感了,面试这东东估计是带有比较浓重的个人风格,我面试的时候喜欢从过往的经验中去找到面试者是否和我们合拍。如有冒犯,还请海涵。

#51 楼 @pzgz

哈哈。没有没有~

chenge Ruby 学习汇集,请推荐内容 提及了此话题。 07月04日 11:35
需要 登录 后方可回复, 如果你还没有账号请 注册新账号