对于“传值”的机制,是为了让被调用者无法更改原始数据。所以被调用者可以以任何方式改变参数变量,但是当函数返回时,参数变量中的原始值并没有改变。
但在 Objective-C 或 Ruby 中,由于对象的所有变量都是对对象的引用,所以当我们将对象传递给任何方法时,该方法都可以“发送消息”来更改对象。方法返回后,调用者将继续使用已经处于不同状态的参数。
或者有没有办法保证传入的对象不改变(它的状态不改变)——有这样的机制吗?
对于“传值”的机制,是为了让被调用者无法更改原始数据。所以被调用者可以以任何方式改变参数变量,但是当函数返回时,参数变量中的原始值并没有改变。
但在 Objective-C 或 Ruby 中,由于对象的所有变量都是对对象的引用,所以当我们将对象传递给任何方法时,该方法都可以“发送消息”来更改对象。方法返回后,调用者将继续使用已经处于不同状态的参数。
或者有没有办法保证传入的对象不改变(它的状态不改变)——有这样的机制吗?
您在这里有点误用了“按值传递”和“按引用传递”一词。你真正在讨论的是const
。在 C++ 中,您可以引用const
可变类的实例。ObjC 对象没有类似的概念(或者我相信在 Ruby 中,尽管我对 Ruby 的熟悉程度远低于 ObjC)。ObjC 确实,通过 C,有const
指针的概念,但这些是一个弱得多的承诺。
在 ObjC 中,最好的解决方案是尽可能优先使用值(不可变)类。有关这方面的更多讨论,请参阅Objective-c 中的 Imutability 。
下一个最佳解决方案是,作为设计问题,避免这种情况。避免名称中不明显的方法中的副作用。通过在设计上避免这种情况,调用者不必担心它。请记住,呼叫者和被呼叫者在同一个团队中。双方都不应该试图保护自己免受对方的伤害。良好的命名和良好的 API 设计可帮助开发人员在没有编译器强制执行的情况下避免错误。ObjC 几乎没有编译器强制执行,因此良好的命名和良好的 API 设计绝对是至关重要的。尽管我在这方面的经验有限,但我对 Ruby 也会这么说,因为它也是一种高度动态的语言。
最后,如果您正在处理一个行为不佳的 API,它在不应该修改您的对象时修改了您的对象,您可以求助于将copy
.
但是,如果您是从头开始设计它,请尽可能考虑使用不可变类。
我不确定你在说什么。Ruby是按值传递的。您不能“更改参数变量”:
def is_ruby_pass_by_value?(foo)
foo = 'No, Ruby is not pass-by-value.'
return nil
end
bar = 'Yes, of course, Ruby *is* pass-by-value!'
is_ruby_pass_by_value?(bar)
p bar
# 'Yes, of course, Ruby *is* pass-by-value!'
我不确定Objective-C,但如果它不同,我会感到惊讶。