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方法吗?
当然,在很多情况下自我是必要的。请注意,这不是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
哪个是模棱两可的-这是方法调用还是新的局部变量分配?
@迈克·斯通
嗨!我理解并感谢您提出的观点,并且您的榜样很棒。当我说的时候,请相信我,如果我有足够的声誉,我会投票赞成你的回答。但是我们仍然不同意:
- 关于语义,以及
- 以事实为中心
首先,我不无讽刺地宣称,我们正在就“歧义”的含义进行语义辩论。
在解析和编程语言语义(这个问题的主题)时,您肯定会接受“歧义”这一概念。让我们采用一些随机符号:
- 模棱两可:词汇歧义(lex必须“向前看”)
- 歧义:语法歧义(yacc必须遵从解析树分析)
- 歧义:执行时一无所知
(还有2-3之间的垃圾)。通过收集更多上下文信息,在全球范围内查找越来越多,可以解决所有这些类别。所以当你说
当未定义变量时,C#中的“ qwerty = 4”是不确定的...
我完全同意。但出于同样的原因,我是说
“ qwerty = 4”在红宝石中是明确的(因为它现在存在)
“ qwerty = 4”在C#中不明确
而且我们还没有相互矛盾。最后,这是我们真正不同意的地方:如果没有任何其他语言结构(例如,
对于“ qwerty = 4”,如果
未定义局部变量,ruby会不确定地调用现有的setter
你说不 我说是; 可能存在另一个在各个方面都与当前行为完全相同的红宝石,只是“ qwerty = 4”在没有设置器且不存在本地变量的情况下定义了一个新变量,如果存在则调用设置器,如果存在则将其分配给本地。我完全接受我可能是错的。实际上,我可能错了的原因很有趣。
让我解释。
想象一下,您正在使用一种类似于实例vars(如ruby和C#)的访问器方法来编写一种新的OO语言。您可能会从以下概念语法开始:
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#,“稍后”仍处于编译时。
我确定ruby可以做到这一点,但是“以后”必须在运行时进行,因为正如ben指出的那样,在执行该语句之前您不知道哪种情况适用。
我的问题从未打算表示“我真的需要'自我'吗?” 或“正在避免什么潜在的歧义?” 而是我想知道为什么要做出这个特定选择?也许不是性能。也许它只是完成了工作,或者最好总是允许一个1-liner局部方法覆盖方法(这是非常罕见的情况要求)...
但我有点建议,最具动态性的语言可能是最长延迟此决定的语言,并根据最上下文的信息选择语义:因此,如果您没有本地语言并且定义了设置器,则将使用该设置器。这不是为什么我们喜欢ruby,smalltalk和objc,因为方法调用是在运行时决定的,从而提供了最大的表达能力吗?
$this->
在访问实例变量时也需要。这让我无时无刻不在。