Ruby 将自定义方法从自定义类传递到.map

Ruby 将自定义方法从自定义类传递到.map,ruby,proc,Ruby,Proc,我正在为exercism.io做一个练习-说明很长,与此问题无关,但您可以找到我的完整解决方案 基本上我有一个Robot类和3个私有方法: def rand_letters ('A'..'Z').to_a[rand(26)] end def rand_numbers (0..9).to_a[rand(10)] end 我要做的是将它们传递给另一个私有方法,如下所示: def set_name @name = ((1..2).map(&:ra

我正在为exercism.io做一个练习-说明很长,与此问题无关,但您可以找到我的完整解决方案

基本上我有一个
Robot
类和3个私有方法:

  def rand_letters
    ('A'..'Z').to_a[rand(26)]
  end

  def rand_numbers
    (0..9).to_a[rand(10)]
  end
我要做的是将它们传递给另一个私有方法,如下所示:

  def set_name
    @name = ((1..2).map(&:rand_letters) + (3..5).map(&:rand_numbers)).join
  end
当我这样做时,我得到一个错误:
未定义的方法'rand_letters'用于1:Fixnum
。看了之后,我想问题可能是我的类没有to_proc方法。不幸的是,我不知道如何纠正这一点。我试着让我的类从
Proc
继承,但我一直在研究如何将
重写为\u Proc
。如果能帮我指明正确的方向,我将不胜感激

以下是解决方案:

def rand_letters
  ('A'..'Z').to_a[rand(26)]
end

def rand_numbers
  (0..9).to_a[rand(10)]
end

p ((1..2).map { rand_letters } + (1..3).map { rand_numbers }).join

当您使用
map(&:rand\u letters)
语法时,您会向集合的每个元素发送消息。在我们的例子中,
Fixnum
对象接收消息(:rand_字母),并且无法响应该消息,因为它未在类
Fixnum
中定义

在我的示例中,消息
:rand_字母
:rand_数字
不会传递给
Fixnum
实例,而是传递给
self
,在那里定义了它们

下面是如何在类中使用它:

class A
  def rand_letters
    ('A'..'Z').to_a[rand(26)]
  end

  def rand_numbers
    (0..9).to_a[rand(10)]
  end

  def name    
    (1..2).map { rand_letters } + (1..3).map { rand_numbers }.join
  end
end

A.new.name

首先:可以使用
array.sample
而不是
array[rand(x)]
从数组中获取随机元素

此外,您可以将
(1..n).map替换为
n.times.map

(2.times.map { rand_letters } + 3.times.map { rand_numbers }).join
但是使用
map
对我来说是违反直觉的。如果我们只需要抓取3个随机字母,不是会容易得多吗

这可以通过返回一个值而不是单个值来实现。复数命名已经表明,
rand
方法应该返回多个值:

def rand_letters
  return enum_for(__method__) unless block_given?
  loop { yield ('A'..'Z').to_a.sample }
end

def rand_numbers
  return enum_for(__method__) unless block_given?
  loop { yield (0..9).to_a.sample }
end
这使我们能够调用:

或者使用
[…]
文字:

[rand_letters.take(2), rand_numbers.take(3)].join

两个问题:这是使用简短语法(
.map(&:method)
的要求的一部分吗如果是-是否允许对
Fixnum
String
类进行猴子补丁?您希望得到什么结果-是否希望将随机字母/数字映射到范围内的每个元素?不,这不是要求的一部分,只是有人在注释中提到过(您可以在完整解决方案的链接上看到)他们建议使用map(&:method),我希望在exercism.io的链接上有两个随机字母和三个数字,例如:BX500,其中有指向我的解决方案之前迭代的链接。如果您愿意,您可以通过浏览我在那里收到的评论,更好地了解正在发生的事情。您可以使用
(1..2).map{rand_letters}
。您也可以用短方法完成,但这需要对
Fixnum
/
String
进行猴子补丁。但是,如果你找到另一种方法,请分享答案。实际上我最终使用了
Array#sample
,所以谢谢你提到它。同时也感谢您的详细解释。这真的让我思考@因此,请注意,
sample(n)
返回
n
唯一元素,即,在您的示例中排除重复元素。
[rand_letters.take(2), rand_numbers.take(3)].join