77

Ruby のセッターは、作成されたか手動で作成されたかにかかわらず、クラス自体内でアクセスするときに修飾(c)attr_accessorが必要な唯一のメソッドのようです。self.これにより、Ruby だけが言語の世界に置かれているようです。

  • すべてのメソッドにはself/が必要ですthis(Perl のように、Javascript だと思います)
  • メソッドは必要ありませんself/ありませんthis(C#、Java)
  • セッターだけがself/ this(Ruby?)を必要とします

最適な比較は C# と Ruby です。どちらの言語も、クラス インスタンス変数のように構文的に機能するアクセサ メソッドをサポートしているためです: foo.x = y, y = foo.x. C# はそれらをプロパティと呼びます。

簡単な例を次に示します。Ruby と C# の同じプログラム:

class A
  def qwerty; @q; end                   # manual getter
  def qwerty=(value); @q = value; end   # manual setter, but attr_accessor is same 
  def asdf; self.qwerty = 4; end        # "self." is necessary in ruby?
  def xxx; asdf; end                    # we can invoke nonsetters w/o "self."
  def dump; puts "qwerty = #{qwerty}"; end
end

a = A.new
a.xxx
a.dump

を取り除くself.qwerty =()と失敗します (Linux および OS X では Ruby 1.8.6)。今C#:

using System;

public class A {
  public A() {}
  int q;
  public int qwerty {
    get { return q; }
    set { q = value; }
  }
  public void asdf() { qwerty = 4; } // C# setters work w/o "this."
  public void xxx()  { asdf(); }     // are just like other methods
  public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}

public class Test {
  public static void Main() {
    A a = new A();
    a.xxx();
    a.dump();
  }
}

質問: これは本当ですか? セッター以外に self が必要な場面はありますか? つまり、Ruby メソッドをselfなしでは呼び出せない場合は他にありますか?

確かにself必要になるケースは多いです。明確にするために、これは Ruby に固有のものではありません。

using System;

public class A {
  public A() {}
  public int test { get { return 4; }}
  public int useVariable() {
    int test = 5;
    return test;
  }
  public int useMethod() {
    int test = 5;
    return this.test;
  }
}

public class Test {
  public static void Main() {
    A a = new A();
    Console.WriteLine("{0}", a.useVariable()); // prints 5
    Console.WriteLine("{0}", a.useMethod());   // prints 4
  }
}

同じあいまいさは同じ方法で解決されます。しかし、微妙な間、私はケースについて尋ねています

  • メソッド定義されており、かつ
  • ローカル変数が定義されていない。

私たちが遭遇する

qwerty = 4

これはメソッドの呼び出しですか、それとも新しいローカル変数の割り当てですか?


@マイク・ストーン

やあ!私はあなたが指摘した点を理解し、感謝しています。あなたの例は素晴らしかったです。私が十分な評判があれば、あなたの回答に賛成票を投じるだろうと私が言うとき、私を信じてください. それでも、私たちはまだ同意しません:

  • セマンティクスの問題について、および
  • 事実の中心点に

まず、皮肉なことに、「あいまいさ」の意味について意味論的な議論が行われていると主張します。

言語のセマンティクス (この質問の主題) の解析とプログラミングに関して言えば、「あいまいさ」という概念の幅広い範囲を認めるでしょう。ランダムな表記法を採用しましょう。

  1. ambiguous: 字句のあいまいさ (lex は「先読み」する必要があります)
  2. あいまい: 文法的なあいまいさ (yacc は解析ツリー分析を延期する必要があります)
  3. AMBIGUOUS: 実行の瞬間にすべてを知っているあいまいさ

(そして、2〜3の間にジャンクもあります)。これらのカテゴリはすべて、コンテキスト情報をさらに収集し、よりグローバルに調査することで解決されます。だからあなたが言うとき、

「qwerty = 4」は、変数が定義されていない場合、C# では UNAMBIGUOUS です...

私はこれ以上同意できませんでした。しかし、同じ理由で、私は言っています

「qwerty = 4」はRubyで明確です(現在存在するため)

"qwerty = 4" は C# ではあいまいです

そして、私たちはまだ互いに矛盾していません。最後に、ここで私たちは本当に同意しません: ruby​​ は、次のような追加の言語構造なしでは実装できるかできないかのどちらかです。


「qwerty = 4」の場合、ローカル変数が定義されていない場合、ruby UNAMBIGUOUSLY は既存のセッターを呼び出します。

あなたはノーと言います。はいと言います。「 qwerty = 4」は、セッターもローカルも存在しない場合に新しい変数定義し、存在する場合はセッターを呼び出し、存在する場合はローカルに割り当てます。私は自分が間違っている可能性があることを完全に受け入れます。実際、私が間違っているかもしれない理由は興味深いでしょう。

説明させてください。

インスタンス変数 (ruby や C# など) のように見えるアクセサ メソッドを使用して、新しいオブジェクト指向言語を作成していると想像してください。おそらく、次のような概念文法から始めるでしょう。

  var = expr    // assignment
  method = expr // setter method invocation

しかし、すべての入力が理解された後でも、どの文法が適切であるかを知る方法がないため、パーサー コンパイラ (ランタイムでさえも) は吐き出します。あなたは古典的な選択に直面しています。詳細はわかりませんが、基本的にRubyはこれを行います:

  var = expr    // assignment (new or existing)
  // method = expr, disallow setter method invocation without .

それがあいまいでない理由です.一方、C#はこれを行います:

  symbol = expr // push 'symbol=' onto parse tree and decide later
                // if local variable is def'd somewhere in scope: assignment
                // else if a setter is def'd in scope: invocation

C# の場合、「後で」はまだコンパイル時です。

ルビーでも同じことができると確信していますが、「後で」は実行時に行う必要があります。なぜなら、ベンが指摘しているように、ステートメントが実行されるまでどのケースが適用されるかわからないからです。

私の質問は、「『自分』が本当に必要なのか?」という意味では決してありませんでした。または「回避されている潜在的なあいまいさは何ですか?」むしろ、なぜこの特定の選択がなされたのか知りたかったのですか? 多分それはパフォーマンスではありません。たぶん、仕事が終わっただけか、1ライナーローカルがメソッドをオーバーライドできるようにするのが最善と考えられていました(かなりまれなケースの要件です)...

しかし、私は、最も動的な言語は、この決定を最も長く延期し、最もコンテキスト情報に基づいてセマンティクスを選択する言語である可能性があることを示唆しています。したがって、ローカルがなく、セッターを定義した場合、セッターが使用されます. メソッドの呼び出しは実行時に決定され、表現力が最大限に発揮されるからです。

4

3 に答える 3

85

ええと、これが当てはまる理由qwerty = 4はあいまいだからだと思います—呼び出される新しい変数を定義していますqwertyか、それともセッターを呼び出していますか? Ruby は、新しい変数を作成すると言ってこのあいまいさを解決するため、self.が必要です。

必要な別のケースを次に示しますself.

class A
  def test
    4
  end
  def use_variable
    test = 5
    test
  end
  def use_method
    test = 5
    self.test
  end
end
a = A.new
a.use_variable # returns 5
a.use_method   # returns 4

ご覧のとおり、 へのアクセスtestがあいまいなため、self.が必要です。

また、セッターを使用して明確な方法で変数を定義するため、これが C# の例が実際には適切な比較ではない理由です。this.C# でアクセサーと同じ名前の変数を定義した場合は、Ruby の場合と同様に、アクセサーへの呼び出しを で修飾する必要があります。

于 2008-09-04T21:04:43.220 に答える
18

ここで覚えておくべき重要なことは、Ruby メソッドはいつでも定義 (未定義) できるということです。したがって、あいまいさをインテリジェントに解決するには、すべての割り当てでコードを実行して、その時点で割り当て先の名前を持つメソッドがあるかどうかを確認する必要があります。割り当ての。

于 2008-09-04T21:28:32.710 に答える
18

そうしないと、メソッド内でローカル変数をまったく設定できないためです。variable = some_valueあいまいです。例えば:

class ExampleClass
  attr_reader :last_set
  def method_missing(name, *args)
    if name.to_s =~ /=$/
      @last_set = args.first
    else
      super
    end
  end

  def some_method
    some_variable = 5 # Set a local variable? Or call method_missing?
    puts some_variable
  end
end

selfセッターに必要でない場合は、some_methodが発生しNameError: undefined local variable or method 'some_variable'ます。ただし、メソッドは意図したとおりに機能します。

example = ExampleClass.new
example.blah = 'Some text'
example.last_set #=> "Some text"
example.some_method # prints "5"
example.last_set #=> "Some text"
于 2014-05-03T18:02:47.163 に答える