รับหัวของฉันรอบ Immutability


13

ฉันยังใหม่ต่อการเขียนโปรแกรมเชิงวัตถุและแนวคิดหนึ่งที่ทำให้ฉันเข้าใจไม่ได้ ฉันคิดว่าหลอดไฟดับไปเมื่อคืน แต่ฉันต้องการยืนยัน:

เมื่อฉันเจอข้อความที่ไม่สามารถเปลี่ยนวัตถุที่ไม่เปลี่ยนรูปได้ฉันก็สับสนเพราะฉันสามารถทำสิ่งต่อไปนี้:

NSString *myName = @"Bob";
myName = @"Mike";

ที่นั่นฉันเพิ่งเปลี่ยน myName ประเภท NSString ที่ไม่เปลี่ยนรูป ปัญหาของฉันคือคำว่า "วัตถุ" สามารถอ้างถึงวัตถุทางกายภาพในหน่วยความจำหรือนามธรรม "myName" คำจำกัดความเดิมใช้กับแนวคิดของการเปลี่ยนแปลงไม่ได้

สำหรับตัวแปรนั้นนิยามของ immutability ที่ชัดเจน (สำหรับฉัน) คือค่าของวัตถุที่ไม่เปลี่ยนรูปสามารถเปลี่ยนได้โดยเปลี่ยนตำแหน่งในหน่วยความจำเช่นการอ้างอิง

ถูกต้องหรือไม่ฉันยังหลงทางอยู่ในป่า?


13
ประเภทของคุณไม่ได้เป็นNSStringมันเป็น " ตัวชี้ไปยังและNSString" ซึ่งไม่เปลี่ยนรูป ฉันรู้อะไรวัตถุประสงค์ C แต่ฉันคาดเดาในตัวอย่างของคุณว่า@"Mike"คือการสร้างตัวอย่างใหม่ของNSStringและการกำหนดให้ตัวชี้myName , ดังนั้นคุณไม่ได้เปลี่ยนวัตถุที่myNameชี้ไปสิ่งที่ชี้ไป
fwgx

2
@fwgx ใส่ไว้เป็นคำตอบแล้วคุณจะได้ upvote ของฉัน
Gulshan

ขอบคุณทุกคนสำหรับคำตอบทั้งหมดพวกเขามีประโยชน์มาก ตอนนี้ฉันรู้สึกว่าวัตถุที่เปลี่ยนไม่ได้คือค่าในหน่วยความจำไม่ใช่ตัวแปรที่ชี้ไปที่มัน
Michael Mangold

@Gulshan เรียบร้อยแล้วโปรดดูด้านล่าง ....
fwgx

เพื่อให้เข้าใจความไม่สามารถเปลี่ยนแปลงได้ฉันขอแนะนำให้เรียนรู้ภาษาการเขียนโปรแกรมที่แยกการเชื่อมโยงอย่างชัดเจน (เช่นการให้ชื่อกับวัตถุ) ด้วยความไม่แน่นอน (เช่นการอนุญาตให้ชื่อถูกกำหนดใหม่ให้กับวัตถุอื่น) ML (ในรูปแบบใด ๆ : SML, Ocaml, F #) เป็นตัวอย่างที่ดี
Gilles 'หยุดชั่วร้าย'

คำตอบ:


4

ดูเหมือนว่าคุณกำลังมุ่งหน้าไปในทิศทางที่ถูกต้อง แต่ยังไม่ได้รับ นี่เป็นสิ่งที่ผิด:

ที่นั่นฉันเพิ่งเปลี่ยน myName ประเภท NSString ที่ไม่เปลี่ยนรูป ปัญหาของฉันคือคำว่า "วัตถุ" สามารถอ้างถึงวัตถุทางกายภาพในหน่วยความจำหรือนามธรรม "myName"

ในข้อมูลโค้ดของคุณmyNameไม่ใช่ประเภทที่ไม่เปลี่ยนรูปแบบNSStringซึ่งเป็นประเภทที่ไม่แน่นอนNSString* (ตัวชี้ไปยัง NSString) ดูเหมือนว่าสิ่งสำคัญที่คุณขาดหายไปคือการเข้าใจว่าตัวชี้เป็นอีกค่าหนึ่งและมันมีชีวิตที่แยกจากตัวชี้ไปที่ (หรือสิ่งต่าง ๆ หากคุณเปลี่ยนส่วนหนึ่งไปตลอดชีวิต)

คุณพูด:

... ค่าของวัตถุที่ไม่เปลี่ยนรูปสามารถเปลี่ยนได้โดยการเปลี่ยนตำแหน่งในหน่วยความจำเช่นการอ้างอิง (หรือที่รู้จักกันว่าตัวชี้)

นี่เป็นสิ่งที่ผิด วัตถุไม่ได้เป็นเจ้าของพอยน์เตอร์ที่ชี้ไปและไม่มีการควบคุมตำแหน่งหน่วยความจำของวัตถุหรือได้รับผลกระทบจากพอยน์เตอร์ใด ๆ

ดังนั้นNSStringวัตถุทั้งสองในตัวอย่างของคุณ ( @"Bob"และ@"Mike") จะแยกออกจากmyNameตัวแปรอย่างสมบูรณ์ พวกเขายังแยกจากกันอย่างสมบูรณ์ เมื่อคุณเปลี่ยนmyNameเป็นชี้ไปที่@"Mike"แทนที่จะชี้ไปที่@"Bob"คุณจะไม่เปลี่ยนNSStringวัตถุ


เพื่อความสมบูรณ์ฉันจะทราบว่าตัวรวบรวมขยะทำให้ซับซ้อนมากขึ้นในการเปลี่ยนแปลงตัวชี้ที่อาจส่งผลกระทบต่อวัตถุที่พวกเขาชี้ไป (ed) อย่างไรก็ตามนี่คือรายละเอียดการใช้งานซึ่งไม่ควรส่งผลกระทบต่อพฤติกรรมที่สังเกตได้ของรหัส


17

คุณหายไปจากคำพูด Immutability หมายถึง: ตราบใดที่คุณไม่เปลี่ยนตัวแปรมันจะ "มี" ค่าเดิมเสมอไม่ว่าคุณจะทำอะไรกับตัวแปรอื่น ๆ

Counterexample ใน C (ลดความซับซ้อนลงเล็กน้อยสมมติว่าสถาปัตยกรรมที่อนุญาต):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

ตอนนี้ไม่มี "ประกอบด้วย" (เช่นจุดที่) สตริง "Hello World" แต่มันคือ "Yello World" แทน

ในภาษาที่สตริงไม่เปลี่ยนรูปเช่น Java และ (แก้ไข: ปลอดภัย) C # คุณไม่สามารถทำได้ ไม่มีทาง. ซึ่งหมายความว่าทุกส่วนของโปรแกรมสามารถเก็บการอ้างอิงไปยังสตริงได้อย่างปลอดภัยและพึ่งพาเนื้อหานั้นไม่เปลี่ยนแปลง มิฉะนั้นพวกเขาจะต้องสร้างสำเนาเพียงเพื่อให้ปลอดภัย

แต่ตัวแปรยังคงไม่แน่นอน คุณสามารถปล่อยให้มันชี้ไปที่วัตถุอื่น เป็นเพียงวัตถุที่ตัวเองจะไม่เปลี่ยนหลังของคุณ


1
ในทางเทคนิคคุณสามารถปรับเปลี่ยนเนื้อหาสตริงใน C # คุณเพียงแค่ต้องใช้unsafeรหัส
Aaronaught

1
Aaronaught: ขอบคุณสำหรับข้อมูลคุณพูดถูก; สำหรับทุกคนที่ต้องการทราบวิธี: msdn.microsoft.com/en-us/library/ms228599.aspx
281377

10

คุณกำลังสับสนตัวแปรกับวัตถุ ตัวแปรสามารถใช้ในการจัดเก็บการอ้างอิงถึงวัตถุ แต่ไม่ใช่วัตถุ มันเป็นวัตถุที่ไม่เปลี่ยนรูปไม่ได้เป็นตัวแปรดังนั้นคุณสามารถเปลี่ยนตัวแปรจากวัตถุหนึ่งไปเป็นวัตถุอื่นได้ แต่คุณไม่สามารถเปลี่ยนคุณลักษณะของวัตถุได้หากไม่เปลี่ยนรูป

คิดว่าวัตถุเป็นเพื่อนบ้านที่เมาเหล้าเสียงดัง หากเขามีเหตุผล (ไม่แน่นอน) คุณอาจจะเคาะประตูของเขาและแปลงเขาเป็นวิถีชีวิตที่เขาไม่ได้ส่งเสียงดัง แต่ถ้าเขาไม่เปลี่ยนรูปการเปลี่ยนแปลงเพียงอย่างเดียวของคุณคือการหวังว่าคนอื่นจะเข้ามา!


3
ฉันมีเพื่อนบ้านที่ฉันอยากจะปิดเสียง
Dave Nay

ฉันไม่คิดว่าคุณต้องการตัวอย่างของคุณในวรรคสองเนื่องจากคำอธิบายของคุณดีพอ IMO ตัวอย่างอาจสับสนได้ อย่างไรก็ตาม +1 สำหรับคำตอบสั้น ๆ สำหรับคำถามของ
Paul McCabe

@DaveNay: ฉันขอโทษสำหรับปุนซ่อนตัว ไม่ได้ตั้งใจเลย
Kilian Foth

6

ตัวแปรไม่ใช่วัตถุ ตัวแปรคือชื่อที่อ้างถึงวัตถุ (หรือโดยทั่วไปจะเป็นค่า)

ตัวอย่างเช่น "ผู้รักษาประตู" เป็นชื่อที่เราใช้อ้างถึงวัตถุ (คน) ที่รับผิดชอบในการปกป้องเป้าหมาย แต่ถ้าฉันแทนที่คนอื่นด้วย (เพราะอดีตได้รับบาดเจ็บหรืออะไรก็ตาม) ตอนนี้คนใหม่จะถูกเรียกว่า "ผู้รักษาประตู"

คำสั่งการกำหนดเป็นสิ่งที่ทำให้ตัวแปรไม่แน่นอน (บางภาษาเช่น Haskell ไม่มีและในความเป็นจริงใช้ตัวแปรที่ไม่เปลี่ยนรูป) จะช่วยให้คุณกำหนดความหมายของชื่อและกำหนดค่าใหม่

ตอนนี้วัตถุสามารถเปลี่ยนแปลงไม่ได้ เมื่อสองสามพันปีก่อนมีใครคิดว่าเพชรนั้นไม่เปลี่ยนรูป ไม่ว่าคุณจะทำอะไรกับเพชรคุณไม่สามารถแก้ไขได้ ไม่ว่าคุณจะเรียกมันว่า waggawooga (แปลว่า "หินมันวาวที่ใหญ่ที่สุดของเผ่าของเรา") หรือหยุดที่จะเรียกมันว่าวิธีนั้น ในทางตรงกันข้ามชิ้นไม้ที่คุณเคยแกะสลักด้วยภาพตลกกับ waggawooga ของคุณไม่เหมือนเดิม มันพิสูจน์แล้วว่าไม่แน่นอน แม้ว่ามันจะมีชื่อเดียวกันตลอดเวลา

ทั้งตัวแปรและค่าสามารถเปลี่ยนแปลงได้ (อิสระ) ในกรณีนี้มันเป็นวัตถุที่ไม่เปลี่ยนรูป เมื่อคุณสร้างNSStringแล้วคุณจะไม่สามารถแก้ไขได้ คุณสามารถเรียกมันว่าชื่อและผ่านมันไปได้ แต่มันจะยังคงเหมือนเดิม ในทางตรงกันข้ามกับที่NSMutableStringสามารถเปลี่ยนแปลงได้หลังจากการสร้างตัวอย่างเช่นโดยการเรียกsetStringวิธีการ


รักการเปรียบเทียบ waggawooga!
Michael K

เพื่อไม่ให้สับสนกับโปสเตอร์ดั้งเดิมเกินความจำเป็นถึงแม้ว่าจุดของคุณที่ตัวแปรนั้นไม่ใช่วัตถุนั้นดี แต่ตัวแปรก็ไม่ได้ถูกนิยามว่าเป็น "ชื่อที่อ้างถึงค่า" อาจตั้งชื่อตัวแปรและอ้างถึงตำแหน่งที่เก็บข้อมูลที่มีค่า ในหลาย ๆ ภาษาตัวแปรการเขียนโปรแกรมไม่จำเป็นต้องตั้งชื่อและในหลาย ๆ ภาษาตัวแปรเดียวกันสามารถมีได้มากกว่าหนึ่งชื่อ
Eric Lippert

4

ฉันคิดว่าคุณรู้สึกหลงทางเพราะคุณกำลังผสมแนวคิดสองอย่าง: วัตถุเองและชื่อตัวแปรที่ผูกกับวัตถุนั้น

วัตถุที่ไม่เปลี่ยนรูปนั้นไม่สามารถเปลี่ยนแปลงได้ ระยะเวลา อย่างไรก็ตามชื่อตัวแปร (สัญลักษณ์) ถูกผูกไว้กับวัตถุที่ไม่เปลี่ยนรูปสามารถปรับเปลี่ยนให้ถูกผูกไว้กับวัตถุอื่นที่ไม่เปลี่ยนรูปได้

สิ่งที่คุณทำในสองบรรทัดนี้คือ:

  1. สร้างวัตถุสตริงที่ไม่เปลี่ยนรูปด้วยค่า "Bob"
  2. ผูกสัญลักษณ์myNameกับวัตถุนั้น
  3. สร้างวัตถุสตริงที่ไม่เปลี่ยนรูปด้วยค่า "ไมค์"
  4. ผูกสัญลักษณ์myNameกับวัตถุนั้น

2

ประเภทของคุณไม่ได้เป็นNSStringมันเป็น " ตัวชี้ไปยังNSString" ซึ่งไม่เปลี่ยนรูป ฉันรู้อะไรวัตถุประสงค์ C แต่ฉันคาดเดาในตัวอย่างของคุณว่า@"Mike"คือการสร้างตัวอย่างใหม่ของNSStringและการกำหนดให้ตัวชี้ myNameดังนั้นคุณไม่ได้เปลี่ยนวัตถุที่myNameถูกชี้ไปเพียงแค่สิ่งที่มันก็ชี้ไปที่


0

นี่คือตัวอย่างของวัตถุที่ไม่แน่นอน: อาร์เรย์ของcharใน C:

char str[10];

ฉันสามารถเปลี่ยนเนื้อหาของstrเป็นเนื้อหาหัวใจของฉัน (ตราบเท่าที่มันไม่เกิน 10 ตัวอักษร) เพื่อให้เป็นที่รู้จักในฐานะสตริงโดยฟังก์ชั่นไลบรารีสตริง C จะต้องมีการต่อท้าย 0 ดังนั้นจึงสามารถเก็บสตริงได้ยาวสูงสุด 9 อักขระ:

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

และเพื่อให้ weiter

ตัดกันกับวัตถุสตริงใน Java:

String foo = "Hello";

อินสแตนซ์สตริง(อันของหน่วยความจำที่มีอักขระ 'H', 'e', ​​'l', 'l' และ 'o') ไม่สามารถแก้ไขได้ ฉันไม่สามารถแก้ไขเนื้อหาใด ๆ ของสตริงนั้นได้ เมื่อคุณเขียนบางอย่างเช่น

foo = foo + " World";

คุณไม่ได้ต่อท้าย "โลก" ต่อท้ายอินสแตนซ์ "Hello" คุณกำลังสร้างอินสแตนซ์ใหม่คัดลอก "Hello World" ไปที่มันและอัปเดตfooเพื่ออ้างถึงอินสแตนซ์สตริงใหม่นั้น

fooตัวเองไม่ได้มีตัวอย่างสตริง; มันอ้างถึงอินสแตนซ์นั้นเท่านั้น (คล้ายกับตัวชี้ใน C หรือ Obj-C) ดังนั้นทำไมประเภทเช่น String จึงถูกเรียกว่าประเภทการอ้างอิง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.