Sự khác biệt giữa bất biến và const


28

Tôi thường thấy các thuật ngữ immutableconstđược sử dụng thay thế cho nhau. Tuy nhiên, từ kinh nghiệm (ít) của tôi, hai người khác nhau rất nhiều trong 'hợp đồng' mà họ thực hiện theo mã:

Bất biến làm cho hợp đồng mà đối tượng này sẽ không thay đổi, dù thế nào (ví dụ: bộ dữ liệu Python, chuỗi Java).

Const làm cho hợp đồng trong phạm vi của biến này sẽ không bị sửa đổi (không có bất kỳ lời hứa nào về những gì các luồng khác có thể làm với đối tượng được chỉ ra trong giai đoạn này, ví dụ như từ khóa C / C ++).

Rõ ràng, cả hai không tương đương, trừ khi ngôn ngữ là một luồng đơn (PHP) hoặc có hệ thống gõ tuyến tính hoặc duy nhất (Clean, Mercury, ATS).

Đầu tiên, sự hiểu biết của tôi về hai khái niệm này có đúng không?

Thứ hai, nếu có sự khác biệt, tại sao chúng hầu như chỉ được sử dụng thay thế cho nhau?


1
constkhông tồn tại trong mọi ngôn ngữ, và tính biến đổi và bất biến không tồn tại trong mọi ngôn ngữ nên việc sử dụng ngôn ngữ này không được áp dụng. Đây là ngôn ngữ cụ thể chỉ khi áp dụng các khái niệm này.

2
Liên quan, khuyến nghị đọc: Các loại bất biến (một vài ví dụ C #, nhưng chủ yếu là bất khả tri ngôn ngữ). Ai đó cho Eric Lippert một huy chương.

Câu trả lời:


14

Tôi sẽ nói chuyện với C ++, nơi sự khác biệt này có liên quan nhất.

Như bạn lưu ý chính xác, bất biến có nghĩa là một đối tượng không thể thay đổi hoàn toàn sau khi tạo. Tất nhiên việc tạo này có thể xảy ra trong thời gian chạy, tức là, một constđối tượng không nhất thiết là hằng số thời gian biên dịch. Trong C ++, một đối tượng là bất biến nếu (1) và (2) hoặc (3) được đáp ứng:

  1. Nó không có thành viên nào được tuyên bố mutablelà bị đột biến bởi constcác chức năng thành viên

  2. Nó được tuyên bố const

  3. constcác chức năng thành viên không sử dụng const_castđể loại bỏ trình constđộ chuyên môn để đột biến bất kỳ thành viên nào

Tuy nhiên, bạn cũng có thể xem xét các công cụ sửa đổi truy cập: nếu một hoạt động bên trong đột biến một thể hiện, nhưng không có tác dụng gì đối với trạng thái của cá thể có thể quan sát được thông qua giao diện công khai của nó, thì đối tượng đó là logic bất biến logic.

Vì vậy, C ++ cung cấp các công cụ cần thiết để tạo các đối tượng bất biến, nhưng giống như hầu hết mọi thứ trong C ++, các công cụ này chỉ đủ tối thiểu và đòi hỏi sự siêng năng để thực sự sử dụng. Trạng thái của một cá thể không nhất thiết bị giới hạn trong các biến thành viên thể hiện vì vì C ++ không cung cấp một cách để thực thi tính minh bạch tham chiếu, nó cũng có thể bao gồm cả trạng thái toàn cầu hoặc lớp.

constcũng có một chức năng khác trong C ++: để đủ điều kiện tham khảo và con trỏ. Một consttài liệu tham khảo có thể đề cập đến một constđối tượng không . Việc sử dụng const_castđể đột biến một đối tượng thông qua một consttham chiếu là hợp pháp (mặc dù không cần thiết hoặc được khuyến khích) nếu và chỉ khi đối tượng đó được tuyên bố là không const:

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

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

Và tất nhiên đó là hành vi không xác định để làm biến đổi một constđối tượng:

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

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

19

Nói cho Java trong đó từ khóa "cuối cùng" đại diện cho "const", hãy xem xét:

final Person someone = new Person();

Điều này có nghĩa là someoneKHÔNG BAO GIỜ có thể đề cập đến đối tượng Người khác. Nhưng, bạn vẫn có thể thay đổi chi tiết về người được giới thiệu. Ví dụsomeone.setMonthlySalary(10000);

Nhưng, nếu someonelà một đối tượng "Bất biến", một trong những điều sau đây sẽ là đúng: (a) Bạn sẽ không có một phương thức có tên setMonthlySalary (b) Gọi setMonthlySalary sẽ luôn đưa ra một ngoại lệ nhưUnsupportedOperationException


10

Các đối tượng bất biến là những đối tượng không thay đổi trạng thái sau khi tạo ra nó. Ví dụ;

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

Trong ví dụ này, đối tượng myComplexStr là bất biến nhưng không phải là hằng số vì giá trị của nó được tính toán. Và nó là bất biến bởi vì nó là một chuỗi và có thuộc tính độ dài tĩnh và không thể thay đổi.

Các đối tượng Const thường được sử dụng để xác định một số hằng số thực có giá trị được biết trước khi biên dịch như Pi, "USA", "StackOverflow.com", số cổng, v.v.

Từ quan điểm này, Const khác với các đối tượng Bất biến vì các giá trị của chúng không được chương trình tính toán.

Nhưng nếu bạn đang nói về từ khóa "const" trong C ++, bạn có thể nói rằng "const" được sử dụng để tạo các đối tượng bất biến.


1
const trong C ++ không tạo các đối tượng bất biến, nó chỉ là một cấp độ truy cập.
Klaim

Bạn có thể giải thích làm thế nào "const double pi = 3.14" không bất biến?
Mert Akcakaya

Vâng, nó phụ thuộc vào nơi nó được. Hãy nói rằng tôi làm: "double * p_pi = const_cast <double *> (& pi); * p_pi = 42;" ví dụ. Sau đó, nếu pi nằm trong không gian toàn cầu hoặc không gian tên, tôi gặp lỗi phân đoạn, nhưng tôi tin rằng, hành vi không xác định, không phải là một lỗi cụ thể. Nếu pi là thành viên của bất kỳ đối tượng nào có sẵn trong thời gian chạy, không phải là tĩnh, tôi nhận được pi == 42. Bạn thấy, thậm chí sử dụng mutable đều khả dụng vì const trong C ++ là về mức độ truy cập, ngữ nghĩa, không phải là bất biến dữ liệu, đó là gần như không thể đạt được trong C ++. Bạn chỉ có thể "mô phỏng" nó. const không phải là bất biến.
Klaim

1
@Klaim Đột biến constnhư thế là hành vi không xác định cho dù được phân bổ ở đâu, IIRC. Và hành vi không xác định là tồi tệ hơn bất kỳ lỗi cụ thể được đảm bảo xảy ra. Điều đó có nghĩa là bạn không sử dụng C ++ nữa - C ++ không cung cấp phương tiện để thay đổi constgiá trị ( mutabletất nhiên ngoại trừ thành viên, nhưng đó không phải là quan điểm của bạn), theo như C ++ có liên quan, bạn không thể làm điều đó. Những triển khai cụ thể nào xảy ra để cho phép là một vấn đề hoàn toàn khác (và tôi cá với bạn, nếu bạn biên dịch với tối ưu hóa, các pha nguy hiểm bạn đã kéo sẽ không ảnh hưởng đến các biểu thức sau này pivì nó đã được thay thế).

"const trong C ++ không tạo các đối tượng bất biến" vẫn sai vì nó vẫn tạo các hằng số toàn cầu như bạn đã nêu trong câu trả lời của riêng bạn. Từ khóa có nghĩa là ngữ nghĩa ở một mức độ nào đó, nếu không, bạn luôn có thể tự thay đổi điện áp của một ô nhớ và thay đổi giá trị của một đối tượng bất biến nếu bạn rất muốn sử dụng các hành vi không xác định.
Mert Akcakaya

8

Đầu tiên, sự hiểu biết của tôi về hai khái niệm này có đúng không?

Có nhưng câu hỏi thứ hai của bạn cho thấy rằng bạn không hiểu những khác biệt này.

Thứ hai, nếu có sự khác biệt, tại sao chúng hầu như chỉ được sử dụng thay thế cho nhau?

const trong C ++ chỉ được sử dụng cho cấp độ truy cập (có nghĩa là "chỉ đọc") , không phải cho bất biến. Nó ngụ ý rằng bản thân truy cập hoàn toàn tách biệt với dữ liệu. Ví dụ, bạn có thể thao tác một số dữ liệu sau đó hiển thị thông qua tham chiếu const. Truy cập ở chế độ chỉ đọc, nhưng chính dữ liệu, vì tất cả các datam đều có thể thay đổi.

const chỉ giới hạn truy cập garantee, trong khi tính không thay đổi (ví dụ như trong D) ngụ ý thực sự không có cách nào để thay đổi dữ liệu ở bất kỳ giai đoạn nào trong vòng đời của đối tượng .

Bây giờ, bạn có thể mô phỏng tính bất biến trong C ++ bằng cách đảm bảo một số dữ liệu không thể được truy cập theo bất kỳ cách nào khác ngoài const và đảm bảo rằng nó được khởi tạo sau đó không được chạm vào nữa. Nhưng đó không phải là một sự đảm bảo mạnh mẽ vì các ngôn ngữ như D mang lại cho bạn khi bạn đánh dấu dữ liệu của mình là không thay đổi. Ngôn ngữ đảm bảo hoàn toàn không thể thực hiện bất kỳ thao tác nào sửa đổi dữ liệu đó, trong khi trong C ++, bạn vẫn có khả năng thay đổi dữ liệu thông qua đúc và biến đổi nếu thực sự cần thiết.

Cuối cùng, nó hoàn toàn không giống nhau vì nó không cung cấp tất cả các bảo đảm tương tự.


3

Nói về JavaScript, các từ khóa constObject.freeze

constáp dụng cho các ràng buộcvariables . Nó tạo ra một ràng buộc bất biến, bạn không thể gán một giá trị mới cho nó.

Object.freezehoạt động trên các giá trị đối tượng. Nó làm cho một đối tượng bất biến . Cụ thể, bạn không thể thay đổi thuộc tính của nó.


0

Trong C ++ chúng giống nhau. Mặc dù bạn có thể thay đổi một constđối tượng nếu bạn có vị trí trong bộ nhớ và quyền của hệ điều hành để ghi vào bộ nhớ đó.


1
Trên thực tế đó là một đối số chống lại chúng giống nhau: C ++ đơn giản là không có từ khóa hoặc hỗ trợ ngôn ngữ bất biến. Và tôi cũng cho rằng lập trình viên sử dụng ngôn ngữ một cách lành mạnh: nếu không, const cũng vậy, hoàn toàn không có giá trị.
K.Steff

1
@ K.Steff - có lẽ tốt hơn để nói rằng không có sự bất biến nào thêm trong C ++ ngoài việc được cung cấp bởi const
Martin Beckett

Hoàn toàn chính xác :)
K.Steff

Trong C ++ chúng không giống nhau chút nào. const là cấp truy cập "chỉ đọc", điều đó không có nghĩa là dữ liệu là bất biến. Bạn có thể bỏ qua nó trong C ++, hầu hết thời gian.
Klaim

0

Trong C, C ++ và các ngôn ngữ liên quan, cũng có một sự khác biệt giữa một đối tượng là const và tham chiếu hoặc con trỏ của bạn đến đối tượng là một tham chiếu không đổi.

Nếu bạn cố gắng sửa đổi một đối tượng không đổi, bạn sẽ có hành vi không xác định. (Bạn có thể Ví dụ, cố gắng sửa đổi một đối tượng không đổi bằng cách lấy địa chỉ của nó, chuyển địa chỉ thành một con trỏ không phải const, sau đó sử dụng con trỏ không const đó để sửa đổi đối tượng).

Mặt khác, con trỏ hoặc tham chiếu không đổi chỉ cho trình biên dịch biết rằng bạn không thể sử dụng con trỏ hoặc tham chiếu này để sửa đổi đối tượng. Bạn có thể bỏ con trỏ hoặc tham chiếu và cố gắng sửa đổi đối tượng. Nếu bản thân đối tượng là không đổi, những điều xấu sẽ xảy ra. Nếu đối tượng không thực sự không đổi, nó sẽ thay đổi. Điều này tất nhiên có thể gây nhầm lẫn cho người dùng mã của bạn và hoàn toàn có thể gây ra lỗi.

Trong C, nếu bạn sử dụng một chuỗi ký tự như "Xin chào", năm ký tự và các byte số 0 thực sự là hằng số, nhưng bạn có được một con trỏ không phải là hằng. Ý tưởng rất tệ khi sử dụng con trỏ non-const đó để thay đổi đối tượng.

Trong C, bạn có thể có một con trỏ "constrict". Điều đó có nghĩa là đối tượng được chỉ là tạm thời không đổi. Nếu đối tượng được sửa đổi bằng bất kỳ phương tiện nào trong khi con trỏ "constrict" nằm trong phạm vi, bạn sẽ có hành vi không xác định. Cái này mạnh hơn con trỏ const chỉ ngăn bạn thay đổi một đối tượng thông qua con trỏ này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.