ไม่เปลี่ยนรูปหมายถึงอะไร?


104

หากสตริงไม่เปลี่ยนรูปหมายความว่า .... (สมมติว่าเป็น JavaScript)

var str = 'foo';

alert(str.substr(1)); // oo

alert(str); // foo

หมายความว่าเมื่อเรียกเมธอดบนสตริงจะส่งคืนสตริงที่แก้ไข แต่จะไม่เปลี่ยนสตริงเริ่มต้นใช่หรือไม่

ถ้าสตริงไม่แน่นอนหมายความว่าสายที่ 2 alert()จะกลับมาooเหมือนกันหรือไม่?

คำตอบ:


105

หมายความว่าเมื่อคุณสร้างอินสแตนซ์วัตถุแล้วคุณจะไม่สามารถเปลี่ยนคุณสมบัติของมันได้ ในการแจ้งเตือนครั้งแรกคุณจะไม่เปลี่ยนฟู คุณกำลังสร้างสตริงใหม่ นี่คือสาเหตุที่ในการแจ้งเตือนครั้งที่สองของคุณมันจะแสดง "foo" แทน oo

หมายความว่าเมื่อเรียกเมธอดบนสตริงจะส่งคืนสตริงที่แก้ไข แต่จะไม่เปลี่ยนสตริงเริ่มต้นใช่หรือไม่

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

หากสตริงไม่แน่นอนหมายความว่าการแจ้งเตือนครั้งที่ 2 () จะส่งคืน oo ด้วยหรือไม่

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


หากมีการแก้ไขและกำหนดสตริงเดียวกันจะอัปเดตสตริง var str = 'foo'; str = str.substr (1)); // oo alert (str); // oo
Ashwin G

สิ่งที่เกี่ยวกับโค้ดด้านล่าง ค่าสตริงมีการเปลี่ยนแปลงในขณะนี้ var name = "Santosh"; console.log (name.substr (0,2)); var name = "kumar" console.log (ชื่อ); ยังคงไม่เปลี่ยนรูป
Santosh

98

ในระดับที่ต่ำกว่าความไม่เปลี่ยนรูปหมายความว่าหน่วยความจำที่เก็บสายอักขระจะไม่ถูกแก้ไข เมื่อคุณสร้างสตริง"foo", "foo"หน่วยความจำบางจะถูกจัดสรรในการจัดเก็บค่า หน่วยความจำนี้จะไม่ถูกเปลี่ยนแปลง ถ้าคุณปรับเปลี่ยนสตริงกับกล่าวว่าสตริงใหม่ถูกสร้างขึ้นและส่วนที่แตกต่างกันของหน่วยความจำจะถูกจัดสรรซึ่งจะเก็บsubstr(1) "oo"ตอนนี้คุณมีสองสตริงในหน่วยความจำ"foo"และ"oo". แม้ว่าคุณจะไม่ได้ใช้"foo"อีกต่อไป แต่ก็ยังคงติดอยู่จนกว่าจะมีการเก็บขยะ

เหตุผลหนึ่งที่การดำเนินการสตริงค่อนข้างแพง


1
ตัวเลขก็ไม่เปลี่ยนรูปเช่นกัน
RN Kushwaha

3
สวัสดีปี 2015 !! "ในระดับที่ต่ำกว่าความไม่เปลี่ยนรูปหมายความว่าหน่วยความจำที่เก็บสายอักขระไว้จะไม่ถูกแก้ไข" --- นี่เป็นข้อ จำกัด เกินไปและฟังดูไม่ถูกต้อง ความไม่เปลี่ยนรูปเป็นเรื่องเกี่ยวกับ userland เท่านั้นหน่วยความจำเสมือนอาจเปลี่ยนแปลงได้เนื่องจากตัวจัดสรรหน่วยความจำชอบทันทีที่มีการเก็บค่าคงที่ของข้อกำหนดของภาษาไว้
zerkms

2
คำตอบนี้มีเหตุผลมากกว่าคำตอบที่ได้รับ
Ejaz Karim

แต่ฉันสามารถทำได้เช่น var str = 'foo'; ฉันสามารถแก้ไขผ่าน str = 'bar' ค่า str ถูกแก้ไขด้วยวิธีนี้ใช่ไหม
Hacker

@Hacker Nope. คุณได้กำหนดสตริงใหม่ให้กับตัวแปรที่ชี้ไปยังตำแหน่งใหม่ในหน่วยความจำ
หลอกลวง

13

ไม่เปลี่ยนรูปหมายถึงสิ่งที่ไม่สามารถเปลี่ยนแปลงหรือแก้ไขได้

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


9

ฉันไม่แน่ใจเกี่ยวกับ JavaScript แต่ใน Java สตริงมีขั้นตอนเพิ่มเติมในการไม่เปลี่ยนรูปโดยใช้ "String Constant Pool" สตริงสามารถสร้างด้วยตัวอักษรสตริง ( "foo") หรือด้วยตัวStringสร้างคลาส สตริงที่สร้างด้วยลิเทอรัลสตริงเป็นส่วนหนึ่งของ String Constant Pool และลิเทอรัลสตริงเดียวกันจะเป็นแอดเดรสหน่วยความจำเดียวกันจากพูลเสมอ

ตัวอย่าง:

    String lit1 = "foo";
    String lit2 = "foo";
    String cons = new String("foo");

    System.out.println(lit1 == lit2);      // true
    System.out.println(lit1 == cons);      // false

    System.out.println(lit1.equals(cons)); // true

ในข้างต้นทั้งสองlit1และlit2สร้างโดยใช้ลิเทอรัลสตริงเดียวกันดังนั้นจึงชี้ไปที่ที่อยู่หน่วยความจำเดียวกัน lit1 == lit2ผลลัพธ์ในtrueให้เนื่องจากเป็นวัตถุเดียวกัน

อย่างไรก็ตามconsสร้างขึ้นโดยใช้ตัวสร้างคลาส แม้ว่าพารามิเตอร์จะเป็นค่าคงที่สตริงเดียวกัน แต่คอนสตรัคเตอร์จะจัดสรรหน่วยความจำใหม่ให้consซึ่งหมายความว่าconsไม่ใช่อ็อบเจ็กต์เดียวกับlit1และlit2แม้ว่าจะมีข้อมูลเดียวกันก็ตาม

แน่นอนเนื่องจากสตริงทั้งสามมีข้อมูลอักขระเดียวกันการใช้equalsวิธีนี้จะคืนค่าจริง

(โครงสร้างสตริงทั้งสองประเภทไม่เปลี่ยนรูปแน่นอน)


3

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

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


3

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

หากสิ่งนี้ดูแปลกให้ฉันเตือนคุณว่าค่ามากมายที่เราใช้ตลอดเวลานั้นไม่เปลี่ยนรูป

var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

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

สตริงไม่ใช่ค่าที่ไม่เปลี่ยนรูปแบบเดียวที่มีอยู่ใน JavaScript ตัวเลขก็ไม่เปลี่ยนรูปเช่นกัน คุณนึกภาพสภาพแวดล้อมที่การประเมินนิพจน์ 2 + 3 เปลี่ยนความหมายของตัวเลข 2 ได้หรือไม่? มันฟังดูไร้สาระ แต่เราทำเช่นนี้กับวัตถุและอาร์เรย์ตลอดเวลา


2

จากสตริงไปจนถึงสแต็ก ... ตัวอย่างที่เข้าใจง่ายนำมาจากบล็อกของ Eric Lippert :

การค้นหาเส้นทางโดยใช้ A * ใน C # 3.0 ตอนที่สอง ...

กองซ้อนที่ไม่แน่นอนเช่น System.Collections.Generic.Stack ไม่เหมาะสมอย่างชัดเจน เราต้องการที่จะสามารถใช้เส้นทางที่มีอยู่และสร้างเส้นทางใหม่จากเส้นทางนี้สำหรับเพื่อนบ้านทั้งหมดขององค์ประกอบสุดท้าย แต่การผลักดันโหนดใหม่ไปยังสแต็กมาตรฐานจะแก้ไขสแต็ก เราต้องทำสำเนาของสแต็กก่อนที่จะผลักดันซึ่งเป็นเรื่องโง่เพราะเราจะทำซ้ำเนื้อหาทั้งหมดโดยไม่จำเป็น

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

หากต้องการเจาะลึกเกี่ยวกับการไม่เปลี่ยนรูปให้อ่านโพสต์ของ Eric ที่เริ่มต้นด้วยบทความนี้:

ความไม่เปลี่ยนรูปใน C # ส่วนที่หนึ่ง: ชนิดของความไม่เปลี่ยนรูป


คำพูดนั้นมีการอ้างสิทธิ์ที่แปลก - โครงสร้างข้อมูลสแต็ก (จริงๆแล้วหลายสแต็กที่มีการแชร์หาง) เป็นโครงสร้างที่ไม่แน่นอนโดยรวมทุกครั้งที่พุชหรือป๊อปจะเปลี่ยนโครงสร้าง เฉพาะแต่ละรายการเท่านั้นที่ไม่เปลี่ยนรูป และโดยหลักการแล้วคุณอาจมีโครงสร้างเหมือนกัน แต่มีองค์ประกอบที่ไม่แน่นอน สิ่งนี้เกิดขึ้นใน IIRC หาสหภาพที่ไม่สามารถแก้ไขได้บางรูปแบบ ความไม่เปลี่ยนรูปมีข้อดีอย่างมาก แต่การแบ่งปันโครงสร้างข้อมูลบางส่วนหรือทั้งหมดเป็นการเพิ่มประสิทธิภาพนั้นเป็นไปได้อย่างสมบูรณ์แบบด้วยการเปลี่ยนแปลง แม้ว่าคุณจะต้องการความไม่เปลี่ยนรูปสำหรับข้อมูลอ้างอิงอื่น ๆ แต่คุณสามารถคัดลอกเมื่อเขียนได้ตลอดเวลาตามต้องการ
Steve314

0

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

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