Ruby ใช้ "การอ้างอิงผ่านวัตถุ"
(การใช้คำศัพท์ของ Python)
ในการพูดว่า Ruby ใช้ "pass by value" หรือ "pass by reference" นั้นไม่ได้มีความหมายเพียงพอที่จะเป็นประโยชน์ ฉันคิดว่าเป็นคนส่วนใหญ่รู้ว่าวันนี้คำศัพท์นั้น ("ค่า" กับ "การอ้างอิง") มาจาก C ++
ใน C ++ "pass by value" หมายถึงฟังก์ชั่นได้รับสำเนาของตัวแปรและการเปลี่ยนแปลงใด ๆ ในการคัดลอกจะไม่เปลี่ยนต้นฉบับ นั่นเป็นความจริงสำหรับวัตถุด้วย หากคุณส่งตัวแปรออบเจ็กต์ตามค่าดังนั้นออบเจ็กต์ทั้งหมด (รวมถึงสมาชิกทั้งหมด) จะถูกคัดลอกและการเปลี่ยนแปลงใด ๆ กับสมาชิกจะไม่เปลี่ยนสมาชิกเหล่านั้นบนออบเจ็กต์ดั้งเดิม (มันแตกต่างกันถ้าคุณผ่านตัวชี้ตามค่า แต่ Ruby ไม่มีตัวชี้ AFAIK)
class A {
public:
int x;
};
void inc(A arg) {
arg.x++;
printf("in inc: %d\n", arg.x); // => 6
}
void inc(A* arg) {
arg->x++;
printf("in inc: %d\n", arg->x); // => 1
}
int main() {
A a;
a.x = 5;
inc(a);
printf("in main: %d\n", a.x); // => 5
A* b = new A;
b->x = 0;
inc(b);
printf("in main: %d\n", b->x); // => 1
return 0;
}
เอาท์พุท:
in inc: 6
in main: 5
in inc: 1
in main: 1
ใน C ++ "pass by reference" หมายถึงฟังก์ชั่นสามารถเข้าถึงตัวแปรต้นฉบับได้ มันสามารถกำหนดจำนวนเต็มตามตัวอักษรใหม่ทั้งหมดและตัวแปรเดิมจะมีค่านั้นด้วย
void replace(A &arg) {
A newA;
newA.x = 10;
arg = newA;
printf("in replace: %d\n", arg.x);
}
int main() {
A a;
a.x = 5;
replace(a);
printf("in main: %d\n", a.x);
return 0;
}
เอาท์พุท:
in replace: 10
in main: 10
Ruby ใช้ pass by value (ในความหมาย C ++) หากอาร์กิวเมนต์ไม่ใช่วัตถุ แต่ใน Ruby ทุกอย่างเป็นวัตถุดังนั้นจึงไม่มีคุณค่าในความรู้สึกของ C ++ ใน Ruby
ใน Ruby มีการใช้ "pass by object reference" (เพื่อใช้คำศัพท์ของ Python):
- ภายในฟังก์ชั่นสมาชิกของวัตถุสามารถกำหนดค่าใหม่ให้กับพวกเขาและการเปลี่ยนแปลงเหล่านี้จะยังคงอยู่หลังจากที่ฟังก์ชั่นกลับมา *
- ภายในฟังก์ชันการกำหนดวัตถุใหม่ทั้งหมดให้กับตัวแปรทำให้ตัวแปรหยุดการอ้างอิงวัตถุเก่า แต่หลังจากฟังก์ชั่นกลับมาตัวแปรเดิมจะยังคงอ้างอิงวัตถุเก่า
ดังนั้น Ruby ไม่ใช้ "pass by reference" ในความหมาย C ++ ถ้าเป็นเช่นนั้นการกำหนดวัตถุใหม่ให้กับตัวแปรภายในฟังก์ชั่นจะทำให้วัตถุเก่าถูกลืมหลังจากฟังก์ชันส่งคืน
class A
attr_accessor :x
end
def inc(arg)
arg.x += 1
puts arg.x
end
def replace(arg)
arg = A.new
arg.x = 3
puts arg.x
end
a = A.new
a.x = 1
puts a.x # 1
inc a # 2
puts a.x # 2
replace a # 3
puts a.x # 2
puts ''
def inc_var(arg)
arg += 1
puts arg
end
b = 1 # Even integers are objects in Ruby
puts b # 1
inc_var b # 2
puts b # 1
เอาท์พุท:
1
2
2
3
2
1
2
1
* นี่คือเหตุผลว่าทำไมใน Ruby หากคุณต้องการแก้ไขวัตถุภายในฟังก์ชั่น แต่ลืมการเปลี่ยนแปลงเหล่านั้นเมื่อฟังก์ชั่นส่งคืนดังนั้นคุณต้องทำสำเนาของวัตถุอย่างชัดเจนก่อนทำการเปลี่ยนแปลงสำเนาชั่วคราว