Ruby setter ーー无论是由 (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 上的 Ruby1.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();
}
}
问题: 这是真的吗?除了赛特以外,还有其他需要自我的场合吗?也就是说,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
这是模糊的ーー这是一个方法调用还是一个新的局部变量赋值?
@ Mike Stone
你好! 我理解并欣赏你提出的观点 相信我,如果我有足够的名声, 我赞成你的回答,但我们仍然意见不一:
首先,我要说的是,并非没有讽刺意味,我们正在进行一场语义上的辩论 「歧义」的涵义。
当涉及到解析和形式语义学时(主题 这个问题) ,你肯定会承认一个广泛的概念 ‘歧义’。让我们采用一些随机符号:
(还有2-3之间的垃圾)。所有这些类别都是通过 收集更多的上下文信息,看得越来越全球化。所以当你 说,
“ qwerty = 4”在 C # 中是不明确的 当没有定义变量时。
我完全同意,但同样的,我要说
“ qwerty = 4”在 Ruby 中是不含糊的 (因为它现在存在)
“ qwerty = 4”在 C # 中是歧义的
我们还没有互相矛盾,最后,这才是我们真正的 不同意: Ruby 可以或不可以在没有任何进一步的 语言结构,
代表“ qwerty = 4”Ruby UNBIGUUSLY 调用现有的 setter
没有定义局部变量
你说不,我说是; 另一个红宝石可能存在,其行为完全相同 在每个方面的电流,除了“ qwerty = 4”定义了一个新的 当没有 setter 和本地存在时,它调用 setter 存在,并且如果存在,它将赋值给局部。我完全接受 可能是错的。事实上,给我一个可能是错的理由会很有趣。
听我解释。
假设您正在编写一种新的 OO 语言,使用访问器方法进行查找 例如 instance vars (例如 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 # ,‘ later’仍然在编译时。
我相信 Ruby 也可以做同样的事情,但是“ later”必须在运行时,因为 正如 Ben 指出的,只有执行了语句,你才能知道是哪种情况 适用。
我的问题从来没有意味着“我真的需要‘自我’吗?”或者“什么。” 避免了潜在的模棱两可?”相反,我想知道这是为什么 特别的选择? 也许不是性能。也许它只是得到了这份工作 否则,最好始终允许1-linerlocal 覆盖 方法(非常罕见的情况下的要求) ..。
但我认为最有活力的语言可能是 推迟这个决定的时间最长,并选择基于最上下文的语义 Info: 所以如果你没有本地的并且你定义了一个 setter,它会使用 setter 这就是为什么我们喜欢 ruby,Smalltalk,objecc,因为方法调用是在运行时决定的, 提供最大的表现力?