簡體   English   中英

具有不尋常語法的Ruby方法

[英]Ruby method with unusual syntax

我有一些方法:

def example_method
  I ♥ world!
end

我對這個方法有兩個問題:

  1. 由於不存在引號,此方法如何不會返回錯誤( example_method不是我的方法)。
  2. 我的問題是,如何讓這種方法回歸'I ♥ too!' 沒有重新定義的字符串,覆蓋此方法。

第2點是我必須解決的練習。

謝謝!

Ruby的語法非常寬容。 當呈現abc形式的元素時,它被解釋為鏈式方法調用: a(b(c))

因此,這意味着需要定義的方法a其接受一個參數,另一b接收一個參數,和一種方法c它返回一些值。

c部分應該是這樣的:

def world!
  "too!"
end

然后你可以用另一種方法鏈接:

def ♥(x)
  "♥ #{x}"
end

此方法名稱似乎不可能,但當前版本的Ruby確實允許方法名稱中的unicode字符。

最后一部分是類似的,留給你練習。

由於不存在引號,此方法如何不會返回錯誤( example_method不是我的方法)。

那么,怎么可能呢

puts foo

是不是SyntaxError 只是因為Ruby讓你省略了隱式接收器和消息發送中參數列表周圍的括號,所以這相當於

self.puts(foo)

無論如何,為什么還要引用? 引用是針對String文字的,但除了Ruby中的String文字之外還有很多其他內容,例如其他文字( IntegerFloatHashArraySymbol s),變量,消息發送等。

我的問題是,如何讓這種方法回歸'I ♥ too!' 沒有重新定義的字符串,覆蓋此方法。

你嘗試過運行嗎? 錯誤消息不僅會回答您的問題#1,還會告訴您如何解決您的問題#2。

example_method
# NoMethodError: undefined method `world!'

好的,所以它告訴我們它找不到一個名為world!的方法world! 我們可以做些什么來解決這個問題? 那么,定義一個怎么樣?

def world!; end

example_method
# NoMethodError: undefined method `♥'

太棒了,我們取得了進步! 現在它告訴我們它找不到名為的方法。 所以,讓我們來定義!

def ♥; end

example_method
# ArgumentError: wrong number of arguments (given 1, expected 0)
# in `♥'

再次進步! Ruby希望我們知道不接受任何爭論,但我們正在傳遞一個。 現在,讓我們忽略所有的論點。

def ♥(_) end

example_method
# NoMethodError: undefined method `I'

好吧,我們已經知道如何解決那個,不是嗎?

def I; end

example_method
# ArgumentError: wrong number of arguments (given 1, expected 0)
# in `I'

而且我們已經看到了一個:

def I(_) end

example_method
# => nil

看起來很有希望! 一切正常,我們只需修復返回值:

def I(_)
  'I ♥ too!'
end

example_method
# => 'I ♥ too!'

而且,我們完成了!

請注意我們甚至不需要做任何實際工作來解決這個練習? 在Ruby的每一步都告訴我們確切的問題是什么,每次解決方案都是微不足道的:Ruby無法找到方法? 讓我們創造一個! Ruby甚至可以幫助我們告訴我們無法找到的方法的名稱,因此我們可以剪切並粘貼它。 Ruby告訴我們,我們正在將參數傳遞給一個不帶任何參數的方法? 讓我們在方法中添加一個參數,Ruby甚至可以幫助我們告訴我們方法的名稱以及需要添加的參數數量。 該方法返回錯誤的值? 只是讓它返回不同的東西!

好的,我們已經完成了,我們已經解決了這個問題。 但我們的解決方案是,由於缺乏一個更好的詞,“無聊”。 現在,一般,無聊還是不錯的 ,無聊的是簡單,枯燥的手段簡單,枯燥的手段,我們沒有做太多的思考,以創建代碼,這意味着任何人最終維護的代碼以后並不需要做的很多想法,這意味着當我們追逐錯誤時,我們不需要做太多思考(換句話說:我們不需要“追查”錯誤,它們會非常明顯並且正確地盯着我們臉)。

但在這種情況下,這是一種鍛煉 ,鍛煉是為了刺激我們。

所以,我們能做些什么? 我們有兩種方法( world! )沒有做任何事情,我們有I沒有使用的參數。 讓我們看看我們如何充分利用它們。

我們注意到句子的結構類似於example_method中的代碼結構。 因此,一個想法是(不是I只是簡單地返回整個句子)每個方法都負責只生成與其在代碼中的位置相對應的句子片段。 那么, world! 也回來'too!' 返回'♥' ,然后I返回'I'

def world!
  'too!'
end

def ♥(_)
  '♥'
end

def I(_)
  'I'
end

example_method
# => 'I'

嗯......好吧,那不是我們想要的。 有什么問題? 啊,我們忘記了這些論點! 我們現在已經使用了兩個未使用的方法,但是我們仍然沒有使用我們未使用的參數。 所以,讓我們看看 - I接受了一個論證, I必須返回字符串'I'后跟......某些東西......我們唯一可用的“東西”就是我們的論點。 讓我們試試如果我們返回字符串'I'后跟參數會發生什么:

def I(rest)
  'I' << rest
end

example_method
# => 'I♥'

那更好。 我們需要添加一個空格:

def I(rest)
  'I ' << rest
end

example_method
# => 'I ♥'

當然,我們也需要句子的其余部分,但幸運的是我們在方法中仍然有一個未使用的參數:

def ♥(rest)
  '♥ ' << rest
end

example_method
# => 'I ♥ too!'

大! 我們現在有一個不再“無聊”的解決方案,它實際上利用了我們所有的方法和參數。 它甚至可以輕松擴展,例如,如果我們想讓它說'I ♥ YOU too!' ,我們只需做一個簡單的改變:

def YOU(rest)
  'YOU ' << rest
end

I ♥ YOU world!
# => 'I ♥ YOU too!'

只有一件事困擾着我。 看看這三種方法:

def ♥(rest)
  '♥ ' << rest
end

def I(rest)
  'I ' << rest
end

def YOU(rest)
  'YOU ' << rest
end

這確實看起來有點重復。 首先,該方法的名稱和字符串文字的值總是相同的,所以每一個方法的重復,其次,所述的三種方法都非常相似,並具有相同的結構。

我們可以得到的方法去掉重復的方法之一是使用Ruby的反射能力,通過使用來獲得訪問方法的體內方法的名稱Kernel#__callee__方法

def ♥(rest)
  "#{__callee__} #{rest}"
end

def I(rest)
  "#{__callee__} #{rest}"
end

def YOU(rest)
  "#{__callee__} #{rest}"
end

如您所見,現在這些方法不僅在結構上相似,而且完全相同。 我們可以通過動態合成方法來消除方法之間的重復,而不是明確地寫出每個方法:

%i[♥ I YOU].each do |method|
  define_method(method) do |rest|
    "#{__callee__} #{rest}"
  end
end

那好多了! 不再重復了。

順便問一下,你注意到了什么嗎? 我忘了測試我們的方法仍然有效! 我們現在就這樣做, 始終每一步 都進行測試!

example_method
# => 'I ♥ too!'

I ♥ YOU world!
# => 'I ♥ YOU too!'

Phew,一切仍然有效。

實際上,現在我們動態合成方法,不再需要使用Kernel#__callee__反射方法,我們的循環知道方法的名稱:

%i[♥ I YOU].each do |method|
  define_method(method) do |rest|
    "#{method} #{rest}"
  end
end

example_method
# => 'I ♥ too!'

I ♥ YOU world!
# => 'I ♥ YOU too!'

我們現在可以做的最后一件事是,而不是合成一組固定的方法,讓我們只回應某人向我們拋出的任何方法。 這就是method_missing的用途:

def method_missing(method, rest)
  "#{method} #{rest}"
end

example_method
# => 'I ♥ too!'

I ♥ YOU world!
# => 'I ♥ YOU too!'

I very much ♥ YOU world!
# => 'I very much ♥ YOU too!'

所以,這是我們所有重構結束時的完整代碼:

def example_method
  I ♥ world!
end

def world!
  'too!'
end

def method_missing(method, rest)
  "#{method} #{rest}"
end

example_method
# => 'I ♥ too!'

I ♥ YOU world!
# => 'I ♥ YOU too!'

I very much ♥ YOU world!
# => 'I very much ♥ YOU too!'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM