ความแตกต่างระหว่างไม่เปลี่ยนรูปและ const


28

ฉันมักจะเห็นคำศัพท์immutableและconstใช้สลับกันได้ อย่างไรก็ตามจากประสบการณ์ (เล็กน้อย) ของฉันทั้งสองต่างกันมากใน 'สัญญา' ที่พวกเขาทำในรหัส:

ไม่เปลี่ยนรูปทำให้สัญญาที่วัตถุนี้จะไม่เปลี่ยนแปลงใด ๆ (เช่น Python tuples, สตริง Java)

Const ทำสัญญาที่อยู่ในขอบเขตของตัวแปรนี้มันจะไม่ถูกแก้ไข (ไม่มีสัญญาใด ๆ เกี่ยวกับสิ่งที่เธรดอื่น ๆ อาจทำกับวัตถุที่ชี้ไปในช่วงเวลานี้เช่นคีย์เวิร์ด C / C ++)

เห็นได้ชัดว่าทั้งสองไม่เทียบเท่ากันยกเว้นภาษานั้นเป็นแบบเธรดเดียว (PHP) หรือมีทั้งระบบการพิมพ์เชิงเส้นหรือแบบ uniquness (Clean, Mercury, ATS)

ครั้งแรกฉันเข้าใจแนวคิดทั้งสองนี้ถูกต้องหรือไม่

ประการที่สองหากมีความแตกต่างทำไมพวกเขาเกือบใช้เฉพาะแทนกันได้?


1
constไม่มีอยู่ในทุกภาษาและความผันแปรและการเปลี่ยนแปลงไม่ได้ไม่มีอยู่ในทุกภาษาดังนั้นการใช้ภาษานี้จึงไม่สามารถใช้งานได้ เป็นภาษาเฉพาะที่ใช้กับแนวคิดเหล่านี้เท่านั้น

2
การอ่านที่แนะนำและเกี่ยวข้อง: ประเภทของความไม่สามารถเปลี่ยนแปลงได้ (ตัวอย่าง C # สองสามข้อ แต่ส่วนใหญ่เป็นผู้ไม่เชื่อเรื่องภาษา) มีคนให้เอริคลิปเพิร์ตหนึ่งเหรียญ

คำตอบ:


14

ฉันจะพูดกับ C ++ ซึ่งความแตกต่างนี้เกี่ยวข้องมากที่สุด

ในขณะที่คุณทราบอย่างถูกต้องไม่เปลี่ยนรูปหมายความว่าวัตถุไม่สามารถเปลี่ยนแปลงได้เลยหลังจากการสร้าง การสร้างนี้สามารถเกิดขึ้นได้ที่รันไทม์เช่นconstวัตถุไม่จำเป็นต้องเป็นค่าคงที่เวลารวบรวม ใน C ++ วัตถุจะไม่เปลี่ยนรูปถ้า (1) และ (2) หรือ (3) เป็นไปตาม:

  1. ไม่มีสมาชิกที่ประกาศmutableว่าจะกลายพันธุ์โดยconstฟังก์ชั่นสมาชิก

  2. มันถูกประกาศ const

  3. constฟังก์ชั่นสมาชิกไม่ได้ใช้const_castเพื่อลบconstคุณสมบัติเพื่อที่จะกลายพันธุ์สมาชิกใด ๆ

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

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

constยังมีฟังก์ชั่นอื่นใน C ++: เพื่อให้การอ้างอิงและพอยน์เตอร์ การconstอ้างอิงอาจหมายถึงconstวัตถุที่ไม่ใช่ มันเป็นเรื่องถูกกฎหมาย (แม้ว่าไม่จำเป็นโดยทั่วไปหรือแนะนำให้เลือก) เพื่อใช้const_castในการกลายพันธุ์วัตถุผ่านการconstอ้างอิงถ้าหากว่าวัตถุนั้นถูกประกาศว่าไม่ใช่const:

int        i = 4;         // Non-const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Legal.

และแน่นอนว่ามันเป็นพฤติกรรมที่ไม่ได้กำหนดไว้เพื่อกลายพันธุ์constวัตถุ:

const int  i = 4;         // const object.
const int* p = &i;        // const pointer.

*const_cast<int*>(p) = 5; // Illegal.

19

สำหรับ Java ที่คำหลัก "final" หมายถึง "const" ให้พิจารณา:

final Person someone = new Person();

หมายความว่าsomeoneไม่สามารถอ้างถึงวัตถุบุคคลอื่นได้ แต่คุณยังสามารถเปลี่ยนรายละเอียดของบุคคลที่ถูกเรียก เช่นsomeone.setMonthlySalary(10000);

แต่ถ้าsomeoneเป็นวัตถุ "ไม่เปลี่ยนรูป" สิ่งใดสิ่งหนึ่งต่อไปนี้จะเป็นจริง: (a) คุณจะไม่มีเมธอดที่ชื่อว่าsetMonthlySalary (b) การเรียก setMonthlySalary จะทำให้เกิดข้อยกเว้นเช่นUnsupportedOperationException


10

วัตถุที่ไม่เปลี่ยนรูปคือวัตถุที่ไม่เปลี่ยนสถานะหลังจากสร้างมัน ตัวอย่างเช่น;

string prefix = "Pre";
string postfix = "Post";
string myComplexStr = prefix + postfix;

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

โดยทั่วไปวัตถุ Const จะใช้เพื่อระบุค่าคงที่จริงบางค่าที่ทราบค่าก่อนการคอมไพล์เช่น Pi, "USA", "StackOverflow.com", หมายเลขพอร์ตและอื่น ๆ

จากมุมมองนี้ Const นั้นแตกต่างจากอ็อบเจกต์ที่ไม่เปลี่ยนรูปเนื่องจากค่าของมันไม่ได้คำนวณโดยโปรแกรม

แต่ถ้าคุณกำลังพูดถึงคำสำคัญ "const" ใน C ++ คุณสามารถพูดได้ว่า "const" ใช้เพื่อสร้างวัตถุที่ไม่เปลี่ยนรูป


1
const ใน C ++ ไม่ได้สร้างวัตถุที่ไม่เปลี่ยนรูปแบบมันเป็นเพียงระดับการเข้าถึง
Klaim

คุณช่วยอธิบายได้อย่างไรว่า "const double pi = 3.14" ไม่เปลี่ยนรูปไม่ได้?
Mert Akcakaya

มันขึ้นอยู่กับว่ามันอยู่ที่ไหน ให้ฉันพูดว่า: "double * p_pi = const_cast <double *> (& pi); * p_pi = 42;" ตัวอย่างเช่น. จากนั้นถ้า pi อยู่ในพื้นที่ส่วนกลางหรือเนมสเปซฉันได้รับข้อผิดพลาดในการแบ่งเซ็กเมนต์ แต่ฉันเชื่อว่าพฤติกรรมที่ไม่ได้กำหนดไม่ใช่ข้อผิดพลาดเฉพาะ ถ้า pi เป็นสมาชิกของวัตถุใด ๆ ที่มีอยู่ที่รันไทม์ที่ไม่คงที่ฉันจะได้รับ pi == 42 คุณเห็นว่าแม้จะใช้การเปลี่ยนแปลงที่ไม่สามารถใช้งานได้เพราะ const ใน C ++ เป็นเรื่องเกี่ยวกับระดับการเข้าถึง เกือบจะเป็นไปไม่ได้ที่จะประสบความสำเร็จใน C ++ คุณสามารถ "จำลอง" ได้เท่านั้น const ไม่เปลี่ยนรูป
Klaim

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

"const ใน C ++ ไม่สร้างวัตถุที่ไม่เปลี่ยนรูป" ยังคงผิดเพราะยังคงสร้างค่าคงที่ทั่วโลกตามที่คุณระบุไว้ในคำตอบของคุณเอง คำหลักคือความหมายของหลักสูตรในบางระดับมิฉะนั้นคุณสามารถเปลี่ยนแรงดันไฟฟ้าของเซลล์หน่วยความจำด้วยตนเองและเปลี่ยนค่าของวัตถุที่ไม่เปลี่ยนรูปถ้าคุณกระตือรือร้นที่จะใช้พฤติกรรมที่ไม่ได้กำหนด
Mert Akcakaya

8

ครั้งแรกฉันเข้าใจแนวคิดทั้งสองนี้ถูกต้องหรือไม่

ใช่ แต่คำถามที่สองของคุณแสดงให้เห็นว่าคุณไม่เข้าใจความแตกต่างเหล่านี้

ประการที่สองหากมีความแตกต่างทำไมพวกเขาเกือบใช้เฉพาะแทนกันได้?

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

const เพียงข้อ จำกัด การเข้าถึงรับประกันในขณะที่เปลี่ยนไม่ได้ (เหมือนใน D ตัวอย่าง) บ่งบอกจริงๆไม่มีทางที่จะเปลี่ยนแปลงข้อมูลที่ใดขั้นตอนของชีวิตของวัตถุ

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

ในท้ายที่สุดมันไม่เหมือนกันเลยเพราะมันไม่ได้มีการรับประกันที่เหมือนกันทั้งหมด


3

การพูดของ JavaScript คำสำคัญconstและObject.freeze

constนำไปใช้กับการผูก variablesมันสร้างการผูกไม่เปลี่ยนรูปคุณไม่สามารถกำหนดค่าใหม่ให้กับมัน

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


0

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


1
ที่จริงแล้วมันเป็นข้อโต้แย้งกับพวกเขาที่เหมือนกัน: C ++ เพียงแค่ไม่มีการสนับสนุนคำหลักหรือภาษาที่ไม่เปลี่ยนรูป และฉันก็สมมติว่าผู้เขียนโปรแกรมใช้ภาษาในลักษณะที่มีเหตุผล: ไม่อย่างนั้น const ก็ไม่มีประโยชน์เช่นกัน
K.Steff

1
@ K.Steff - อาจจะดีกว่าที่จะบอกว่าไม่มีลักษณะพิเศษที่ไม่เปลี่ยนรูปแบบใน C ++ นอกเหนือจากที่จัดทำโดย const
มาร์ติน Beckett

แม่นยำอย่างแน่นอน :)
K.Steff

ใน C ++ พวกมันไม่เหมือนกันเลย const คือระดับการเข้าถึงแบบอ่านอย่างเดียวไม่ได้หมายความว่าข้อมูลไม่เปลี่ยนรูป คุณสามารถเลี่ยงได้ใน C ++ ส่วนใหญ่
Klaim

0

ใน C, C ++ และภาษาที่เกี่ยวข้องนอกจากนี้ยังมีความแตกต่างระหว่างวัตถุที่เป็น const และการอ้างอิงหรือตัวชี้ของคุณไปยังวัตถุที่เป็นการอ้างอิงคงที่

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

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

ใน C ถ้าคุณใช้ตัวอักษรสตริงเช่น "Hello" ห้าตัวอักษรและศูนย์ไบต์ต่อท้ายจะคงที่ แต่คุณจะได้รับตัวชี้ที่ไม่ใช่ const ความคิดที่ดีมากในการใช้ตัวชี้ที่ไม่ใช่ const นั้นเพื่อเปลี่ยนวัตถุ

ใน C คุณสามารถมีตัวชี้ "const const" นั่นหมายความว่าวัตถุที่ชี้ไปนั้นคงที่ชั่วคราว หากวัตถุนั้นได้รับการแก้ไขโดยวิธีการใด ๆ ในขณะที่ตัวชี้ "const const" อยู่ในขอบเขตคุณจะได้รับพฤติกรรมที่ไม่ได้กำหนด สิ่งนี้แข็งแกร่งกว่าตัวชี้ const ซึ่งป้องกันไม่ให้คุณเปลี่ยนวัตถุผ่านตัวชี้นี้เท่านั้น

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