2

私はいつも、スタイルの好み (言葉が少ないほど簡潔) のために、ルビストが ruby​​ で return を暗黙的にすることを選択していると考えていました。ただし、次の例では、実際に戻り値を暗黙的にする必要があることを誰かが確認できますか? そうしないと、意図した機能が機能しません。(意図された機能は、文を単語に分割し、各単語に対して「母音で始まる」または「子音で始まる」のいずれかを返すことができるようにすることです)

# With Implicit Returns
def begins_with_vowel_or_consonant(words)
  words_array = words.split(" ").map do |word|
    if "aeiou".include?(word[0,1])
      "Begins with a vowel" # => This is an implicit return
    else
      "Begins with a consonant" # => This is another implicit return
    end
  end
end

# With Explicit Returns
def begins_with_vowel_or_consonant(words)
  words_array = words.split(" ").map do |word|
    if "aeiou".include?(word[0,1])
      return "Begins with a vowel" # => This is an explicit return
    else
      return "Begins with a consonant" # => This is another explicit return
    end
  end
end

さて、このコードをより効率的かつ優れたものにする方法がたくさんあることは確かですが、このようにレイアウトした理由は、暗黙的な戻り値の必要性を説明するためです。文体の選択だけでなく、暗黙のリターンが実際に必要であることを誰かが確認できますか?

編集:これは、私が見せようとしていることを説明するための例です:

# Implicit Return
begins_with_vowel_or_consonant("hello world") # => ["Begins with a consonant", "Begins with a consonant"] 

# Explicit Return
begins_with_vowel_or_consonant("hello world") # => "Begins with a consonant" 
4

3 に答える 3

5

メソッドの暗黙的な戻り値は、メソッドで評価される最後の式です。

あなたの場合、注釈を付けた2行はどちらも最後の式ではありません。評価される最後の式はへの代入ですwords_array(BTW は最後の式であるため、後でその変数を使用する方法がないため、まったく役に立ちません)。

では、代入式の値は何でしょうか? mapこれは、割り当てられる値であり、この特定のケースでは、メソッドの戻り値であり、 Array. したがって、それがメソッドが返すものです。

2番目の例では、 の最初の繰り返しで、2 つの のうちのmap1 つにヒットreturnし、メソッドからすぐに戻ります。ただし、最初の例では、常にwords配列全体を反復処理します。

問題は、暗黙の戻り値と明示的な戻り値が異なることではありません。問題は、暗黙の戻り値であると主張する2行がそうではないことです。

于 2013-03-03T16:11:28.680 に答える
1

これが発生する理由は、return ステートメントがブロック内にあるためです。return ステートメントが関数内にある場合、実行フローは期待どおりになります。ruby のブロックとリターン (およびそのための break ステートメント) は奇妙な獣です。あなたが求めていることを捉えるために、より簡単な例を見てみましょう:

def no_return()
  (1..10).each do |i|
    puts i
  end
  puts 'end'
end

def yes_return()
  (1..10).each do |i|
    puts i
    return 
  end
  puts 'end'
end

これらの両方を実行すると、最初の関数では予想どおり 1 ~ 10 の数字と「end」という単語が出力されることがわかりますが、2 番目の関数では 1 しか出力されません。および break ステートメント) を例外として使用します。これらの例外がスローされると、「キャッチ テーブル」と呼ばれるルックアップ テーブルを使用して、実行フローを続行する場所を探します。何も見つからない場合、ruby は内部的に rb_control_frame 構造体のスタックを調べて、実行中のコードを指すポインターを探します。したがって、あなたの場合、例外がスローされ、(スタック フレームに関して) 最も近いポインターがメソッドの最後にあり、本質的にメソッド全体が終了します。そのため、「終わり」が表示されることさえありません。

no_return 手順:

0000 trace            1                                               (   3)
0002 putnil           
0003 getdynamic       i, 0
0006 send             :puts, 1, nil, 8, <ic:0>
0012 leave    

yes_return 手順:

0000 trace            1                                               (   3)
0002 putnil           
0003 getdynamic       i, 0
0006 send             :puts, 1, nil, 8, <ic:0>
0012 pop              
0013 trace            1                                               (   4)
0015 putnil           
0016 throw            1
0018 leave 

重要なビットは yes_return 命令にあります。実際には、スローされた (およびキャッチされた) 例外として実装された return ステートメントである「throw 1」があります。ブレークは、'throw 2' を除いて同じように機能します。

すべてのフレームとキャッチ テーブルの実際の手順を自分で確認するには、私が少し前に作成したこのアプリをチェックしてください: http://rubybytes.herokuapp.com/

詳細については、Pat Shaughnessy のブログを参照してください。詳細については、このエントリを参照してください: http://patshaughnessy.net/2012/6/29/how-ruby-executes-your-code

もう 1 つの恥知らずなプラグインです。Java に興味がある場合は、javabytes.herokuapp.com で私の Java バージョンの ruby​​bytes をチェックして、逆アセンブルされた Java バイトコードを確認してください (リンクがなくて申し訳ありません。URL をコピーしてブラウザーに貼り付ける必要があります)。 )。

于 2013-03-03T16:49:28.130 に答える
0

returnブロックに生成されたメソッドから戻るため、暗黙的であるか、次に使用する必要があります

于 2013-03-03T16:25:45.123 に答える