"Loại an toàn" có nghĩa là gì?
"Loại an toàn" có nghĩa là gì?
Câu trả lời:
Loại an toàn có nghĩa là trình biên dịch sẽ xác nhận các loại trong khi biên dịch và đưa ra lỗi nếu bạn cố gán sai loại cho một biến.
Một số ví dụ đơn giản:
// Fails, Trying to put an integer in a string
String one = 1;
// Also fails.
int foo = "bar";
Điều này cũng áp dụng cho các đối số phương thức, vì bạn đang truyền các kiểu rõ ràng cho chúng:
int AddTwoNumbers(int a, int b)
{
return a + b;
}
Nếu tôi đã cố gắng gọi nó bằng cách sử dụng:
int Sum = AddTwoNumbers(5, "5");
Trình biên dịch sẽ đưa ra một lỗi, bởi vì tôi đang truyền một chuỗi ("5") và nó đang mong đợi một số nguyên.
Trong một ngôn ngữ được gõ lỏng lẻo, chẳng hạn như javascript, tôi có thể làm như sau:
function AddTwoNumbers(a, b)
{
return a + b;
}
nếu tôi gọi nó như thế này:
Sum = AddTwoNumbers(5, "5");
Javascript tự động chuyển đổi 5 thành một chuỗi và trả về "55". Điều này là do javascript sử dụng dấu + để nối chuỗi. Để làm cho nó nhận biết kiểu, bạn sẽ cần phải làm một cái gì đó như:
function AddTwoNumbers(a, b)
{
return Number(a) + Number(b);
}
Hoặc, có thể:
function AddOnlyTwoNumbers(a, b)
{
if (isNaN(a) || isNaN(b))
return false;
return Number(a) + Number(b);
}
nếu tôi gọi nó như thế này:
Sum = AddTwoNumbers(5, " dogs");
Javascript tự động chuyển đổi 5 thành một chuỗi và nối thêm chúng, để trả về "5 con chó".
Không phải tất cả các ngôn ngữ động đều dễ tha thứ như javascript (Trên thực tế, một ngôn ngữ động không có nghĩa là một ngôn ngữ được gõ lỏng lẻo (xem Python)), một số ngôn ngữ thực sự sẽ cung cấp cho bạn lỗi thời gian chạy khi truyền kiểu không hợp lệ.
Mặc dù tiện lợi nhưng nó mở ra cho bạn rất nhiều lỗi có thể dễ dàng bỏ qua và chỉ được xác định bằng cách kiểm tra chương trình đang chạy. Cá nhân, tôi thích để trình biên dịch của tôi nói với tôi nếu tôi mắc lỗi đó.
Bây giờ, quay lại C # ...
C # hỗ trợ một tính năng ngôn ngữ gọi là hiệp phương sai , về cơ bản điều này có nghĩa là bạn có thể thay thế một loại cơ sở cho một loại con và không gây ra lỗi, ví dụ:
public class Foo : Bar
{
}
Ở đây, tôi đã tạo một lớp mới (Foo) mà phân lớp Bar. Bây giờ tôi có thể tạo một phương thức:
void DoSomething(Bar myBar)
Và gọi nó bằng cách sử dụng Foo hoặc Bar làm đối số, cả hai sẽ hoạt động mà không gây ra lỗi. Điều này hoạt động vì C # biết rằng bất kỳ lớp con nào của Bar sẽ thực hiện giao diện của Bar.
Tuy nhiên, bạn không thể thực hiện ngược lại:
void DoSomething(Foo myFoo)
Trong tình huống này, tôi không thể truyền Bar cho phương thức này, vì trình biên dịch không biết rằng Bar thực hiện giao diện của Foo. Điều này là do một lớp con có thể (và thường sẽ) khác nhiều so với lớp cha.
Tất nhiên, bây giờ tôi đã đi đến tận cùng và vượt ra ngoài phạm vi của câu hỏi ban đầu, nhưng đó là tất cả những điều tốt để biết :)
Không nên nhầm lẫn kiểu an toàn với kiểu gõ tĩnh / động hoặc gõ mạnh / yếu.
Ngôn ngữ an toàn loại là một ngôn ngữ trong đó các hoạt động duy nhất mà người ta có thể thực hiện trên dữ liệu là những hoạt động được loại bởi loại dữ liệu. Đó là, nếu dữ liệu của bạn thuộc loại X
và X
không hỗ trợ hoạt động y
, thì ngôn ngữ sẽ không cho phép bạn thực thi y(X)
.
Định nghĩa này không đặt ra quy tắc khi điều này được kiểm tra. Nó có thể ở thời gian biên dịch (gõ tĩnh) hoặc tại thời gian chạy (gõ động), thường thông qua các ngoại lệ. Nó có thể là một chút của cả hai: một số ngôn ngữ được nhập tĩnh cho phép bạn truyền dữ liệu từ loại này sang loại khác và phải kiểm tra tính hợp lệ của phôi trong thời gian chạy (hãy tưởng tượng rằng bạn đang cố gắng chuyển Object
sang một Consumer
- trình biên dịch không có cách để biết liệu nó có thể chấp nhận hay không).
An toàn loại không nhất thiết có nghĩa là gõ mạnh, một số ngôn ngữ được đánh máy yếu, nhưng vẫn được cho là an toàn. Lấy Javascript, ví dụ: hệ thống loại của nó yếu như chúng đến, nhưng vẫn được xác định nghiêm ngặt. Nó cho phép tự động truyền dữ liệu (giả sử, chuỗi thành ints), nhưng trong các quy tắc được xác định rõ. Theo hiểu biết của tôi, không có trường hợp chương trình Javascript nào hoạt động theo kiểu không xác định và nếu bạn đủ thông minh (tôi không), bạn sẽ có thể dự đoán điều gì sẽ xảy ra khi đọc mã Javascript.
Một ví dụ về ngôn ngữ lập trình không an toàn kiểu là C: đọc / ghi giá trị mảng bên ngoài giới hạn của mảng có hành vi không xác định theo đặc tả . Không thể dự đoán những gì sẽ xảy ra. C là ngôn ngữ có hệ thống loại, nhưng không phải là loại an toàn.
Loại an toàn không chỉ là một ràng buộc thời gian biên dịch, mà là một hạn chế thời gian chạy . Tôi cảm thấy thậm chí sau tất cả thời gian này, chúng ta có thể thêm rõ ràng hơn cho điều này.
Có 2 vấn đề chính liên quan đến an toàn loại. Bộ nhớ ** và kiểu dữ liệu (với các hoạt động tương ứng của nó).
Một char
thường đòi hỏi 1 byte cho mỗi ký tự, hoặc 8 bit (phụ thuộc vào ngôn ngữ, Java và C chars unicode # cửa hàng mà yêu cầu 16 bit). An int
yêu cầu 4 byte, hoặc 32 bit (thường).
Trực quan:
char: |-|-|-|-|-|-|-|-|
int : |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Một ngôn ngữ an toàn loại không cho phép một int được chèn vào char trong thời gian chạy (điều này sẽ loại bỏ một số loại cast hoặc ngoại lệ bộ nhớ). Tuy nhiên, trong một ngôn ngữ không an toàn, bạn sẽ ghi đè lên dữ liệu hiện có trong 3 byte bộ nhớ liền kề.
int >> char:
|-|-|-|-|-|-|-|-| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?| |?|?|?|?|?|?|?|?|
Trong trường hợp trên, 3 byte ở bên phải được ghi đè, do đó, bất kỳ con trỏ nào tới bộ nhớ đó (giả sử 3 ký tự liên tiếp) dự kiến sẽ nhận được giá trị char dự đoán sẽ có rác. Điều này gây ra undefined
hành vi trong chương trình của bạn (hoặc tệ hơn, có thể trong các chương trình khác tùy thuộc vào cách hệ điều hành phân bổ bộ nhớ - rất khó xảy ra trong những ngày này).
** Mặc dù vấn đề đầu tiên này không phải là về mặt kỹ thuật về kiểu dữ liệu, hãy nhập ngôn ngữ an toàn vốn có và nó mô tả trực quan vấn đề cho những người không biết về cách phân bổ bộ nhớ "trông".
Vấn đề loại trực tiếp và tinh tế hơn là hai loại dữ liệu sử dụng cùng cấp phát bộ nhớ. Lấy một int so với một int unsign. Cả hai đều là 32 bit. (Cũng dễ như có thể là char [4] và int, nhưng vấn đề phổ biến hơn là uint vs. int).
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
|-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-| |-|-|-|-|-|-|-|-|
Một ngôn ngữ không an toàn cho phép lập trình viên tham chiếu khoảng 32 bit được phân bổ hợp lý, nhưng khi giá trị của một số nguyên không dấu được đọc vào khoảng trống của một int (hoặc ngược lại), chúng ta lại có undefined
hành vi. Hãy tưởng tượng những vấn đề này có thể gây ra trong một chương trình ngân hàng:
"Anh bạn! Tôi đã thấu chi $ 30 và bây giờ tôi còn lại $ 65,506 !!"
... 'Tất nhiên, các chương trình ngân hàng sử dụng các loại dữ liệu lớn hơn nhiều. ;) CƯỜI LỚN!
Như những người khác đã chỉ ra, vấn đề tiếp theo là các hoạt động tính toán trên các loại. Điều đó đã được bảo hiểm đầy đủ.
Hầu hết các lập trình viên ngày nay không bao giờ cần phải lo lắng về những điều như vậy trừ khi họ đang sử dụng một cái gì đó như C hoặc C ++. Cả hai ngôn ngữ này đều cho phép lập trình viên dễ dàng vi phạm an toàn loại trong thời gian chạy (tham chiếu bộ nhớ trực tiếp) bất chấp những nỗ lực tốt nhất của trình biên dịch để giảm thiểu rủi ro. TUY NHIÊN, đây không phải là tất cả xấu.
Một lý do khiến các ngôn ngữ này quá nhanh về mặt tính toán là chúng không bị gánh nặng khi xác minh tính tương thích của loại trong các hoạt động thời gian chạy như, ví dụ, Java. Họ cho rằng nhà phát triển là một người có lý trí tốt, họ sẽ không thêm một chuỗi và một int với nhau và vì thế, nhà phát triển được thưởng bằng tốc độ / hiệu quả.
Nhiều câu trả lời ở đây kết hợp an toàn kiểu với gõ tĩnh và gõ động. Một ngôn ngữ được gõ động (như smalltalk) cũng có thể là loại an toàn.
Một câu trả lời ngắn: một ngôn ngữ được coi là an toàn nếu không có hoạt động dẫn đến hành vi không xác định. Nhiều người coi yêu cầu chuyển đổi kiểu tường minh cần thiết cho một ngôn ngữ được nghiêm gõ, như chuyển đổi tự động đôi khi có thể dẫn đến những hành vi được xác định rõ nhưng bất ngờ / unintuitive.
if no operation leads to undefined behavior
.
Một lời giải thích từ một chuyên ngành nghệ thuật tự do, không phải là một chuyên ngành khoa học:
Khi mọi người nói rằng một tính năng ngôn ngữ hoặc ngôn ngữ là loại an toàn, điều đó có nghĩa là ngôn ngữ đó sẽ giúp ngăn bạn, ví dụ, chuyển một cái gì đó không phải là số nguyên cho một số logic mong đợi một số nguyên.
Ví dụ: trong C #, tôi định nghĩa một hàm là:
void foo(int arg)
Trình biên dịch sau đó sẽ ngăn tôi làm điều này:
// call foo
foo("hello world")
Trong các ngôn ngữ khác, trình biên dịch sẽ không dừng tôi (hoặc không có trình biên dịch ...), do đó, chuỗi sẽ được chuyển đến logic và sau đó có thể có điều gì đó xấu sẽ xảy ra.
Nhập ngôn ngữ an toàn cố gắng nắm bắt nhiều hơn vào "thời gian biên dịch".
Ở phía bên dưới, với các ngôn ngữ an toàn, khi bạn có một chuỗi như "123" và bạn muốn hoạt động trên nó như int, bạn phải viết thêm mã để chuyển đổi chuỗi thành int hoặc khi bạn có int như 123 và muốn sử dụng nó trong một thông điệp như "Câu trả lời là 123", bạn phải viết thêm mã để chuyển đổi / chuyển nó thành một chuỗi.
Để hiểu rõ hơn, hãy xem video dưới đây thể hiện mã bằng ngôn ngữ an toàn (C #) và KHÔNG gõ ngôn ngữ an toàn (javascript).
http://www.youtube.com/watch?v=Rlw_njQhkxw
Bây giờ cho các văn bản dài.
Loại an toàn có nghĩa là ngăn ngừa lỗi loại. Lỗi loại xảy ra khi loại dữ liệu của một loại được gán cho loại khác KHÔNG GIỚI HẠN và chúng tôi nhận được kết quả không mong muốn.
Ví dụ, JavaScript không phải là ngôn ngữ an toàn. Trong đoạn mã dưới đây, num num num là một biến số và kiểu str str là chuỗi. Javascript cho phép tôi thực hiện kiểu num num + str, bây giờ GUESS sẽ thực hiện số học hoặc ghép.
Bây giờ với mã bên dưới, kết quả là 55, nhưng điểm quan trọng là sự nhầm lẫn được tạo ra sẽ thực hiện loại hoạt động nào.
Điều này đang xảy ra vì javascript không phải là một ngôn ngữ an toàn. Nó cho phép đặt một loại dữ liệu sang loại khác mà không bị hạn chế.
<script>
var num = 5; // numeric
var str = "5"; // string
var z = num + str; // arthimetic or concat ????
alert(z); // displays “55”
</script>
C # là một ngôn ngữ an toàn. Nó không cho phép một loại dữ liệu được gán cho loại dữ liệu khác. Đoạn mã dưới đây không cho phép toán tử của Wap + trên các loại dữ liệu khác nhau.
Loại an toàn có nghĩa là lập trình, loại dữ liệu cho một biến, giá trị trả về hoặc đối số phải phù hợp với một tiêu chí nhất định.
Trong thực tế, điều này có nghĩa là 7 (một kiểu số nguyên) khác với "7" (một ký tự được trích dẫn của loại chuỗi).
PHP, Javascript và các ngôn ngữ kịch bản động khác thường được gõ yếu, trong đó chúng sẽ chuyển đổi một (chuỗi) "7" thành (số nguyên) 7 nếu bạn cố gắng thêm "7" + 3, mặc dù đôi khi bạn phải làm điều này rõ ràng (và Javascript sử dụng ký tự "+" để ghép nối).
C / C ++ / Java sẽ không hiểu điều đó hoặc thay vào đó sẽ ghép kết quả thành "73". Loại an toàn ngăn chặn các loại lỗi trong mã bằng cách làm rõ yêu cầu loại.
Loại an toàn là rất hữu ích. Giải pháp cho "7" + 3 ở trên sẽ là gõ cast (int) "7" + 3 (bằng 10).
Ý tưởng:
Để rất đơn giản Loại An toàn như ý nghĩa, đảm bảo rằng loại biến đó phải an toàn như
vì vậy tất cả là về sự an toàn của các loại lưu trữ của bạn về các biến.
Hãy thử giải thích này trên ...
TypeSafe có nghĩa là các biến được kiểm tra tĩnh để gán phù hợp tại thời điểm biên dịch. Ví dụ, giao một chuỗi hoặc một số nguyên. Hai loại dữ liệu khác nhau này không thể được gán chéo (nghĩa là bạn không thể gán một số nguyên cho một chuỗi cũng như bạn không thể gán một chuỗi cho một số nguyên).
Đối với hành vi không an toàn, hãy xem xét điều này:
object x = 89;
int y;
nếu bạn cố gắng làm điều này:
y = x;
trình biên dịch đưa ra một lỗi cho biết nó không thể chuyển đổi System.Object thành Integer. Bạn cần phải làm điều đó một cách rõ ràng. Một cách sẽ là:
y = Convert.ToInt32( x );
Nhiệm vụ trên không an toàn. Phân công an toàn kiểu là nơi các loại có thể được gán trực tiếp cho nhau.
Các bộ sưu tập không an toàn có rất nhiều trong ASP.NET (ví dụ: các bộ sưu tập ứng dụng, phiên và viewstate). Tin tốt về các bộ sưu tập này là (giảm thiểu nhiều cân nhắc quản lý trạng thái máy chủ), bạn có thể đặt khá nhiều loại dữ liệu vào bất kỳ bộ sưu tập nào trong ba bộ sưu tập. Tin xấu: vì các bộ sưu tập này không an toàn, bạn sẽ cần truyền các giá trị một cách thích hợp khi bạn lấy chúng ra.
Ví dụ:
Session[ "x" ] = 34;
hoạt động tốt Nhưng để gán lại giá trị số nguyên, bạn sẽ cần:
int i = Convert.ToInt32( Session[ "x" ] );
Đọc về thuốc generic cho những cách mà cơ sở giúp bạn dễ dàng thực hiện các bộ sưu tập an toàn.
C # là một ngôn ngữ an toàn nhưng xem các bài viết về C # 4.0; khả năng năng động thú vị hiện ra (có phải là một điều tốt khi C # về cơ bản nhận được Option Strict: Tắt ... chúng ta sẽ thấy).
Type-Safe là mã chỉ truy cập các vị trí bộ nhớ mà nó được phép truy cập và chỉ theo những cách được xác định rõ, cho phép. Mã an toàn loại không thể thực hiện một thao tác trên một đối tượng không hợp lệ cho đối tượng đó. Trình biên dịch ngôn ngữ C # và VB.NET luôn tạo mã an toàn kiểu, được xác minh là an toàn kiểu trong quá trình biên dịch JIT.
Loại an toàn có nghĩa là tập hợp các giá trị có thể được gán cho biến chương trình phải phù hợp với tiêu chí được xác định rõ và có thể kiểm tra. Các biến an toàn loại dẫn đến các chương trình mạnh mẽ hơn vì các thuật toán thao tác các biến có thể tin tưởng rằng biến đó sẽ chỉ lấy một trong các tập hợp giá trị được xác định rõ. Giữ sự tin tưởng này đảm bảo tính toàn vẹn và chất lượng của dữ liệu và chương trình.
Đối với nhiều biến, tập hợp các giá trị có thể được gán cho một biến được xác định tại thời điểm chương trình được viết. Ví dụ: một biến được gọi là "màu" có thể được phép nhận các giá trị "đỏ", "xanh" hoặc "xanh" và không bao giờ có bất kỳ giá trị nào khác. Đối với các biến khác, các tiêu chí có thể thay đổi vào thời gian chạy. Ví dụ: một biến có tên "màu" chỉ có thể được phép nhận các giá trị trong cột "tên" của bảng "Màu" trong cơ sở dữ liệu quan hệ, trong đó "đỏ," xanh "và" xanh "là ba giá trị cho "tên" trong bảng "Màu sắc", nhưng một số phần khác của chương trình máy tính có thể có thể thêm vào danh sách đó trong khi chương trình đang chạy và biến có thể nhận các giá trị mới sau khi chúng được thêm vào bảng Màu sắc .
Nhiều ngôn ngữ an toàn loại cho ảo tưởng về "an toàn loại" bằng cách nhấn mạnh vào việc xác định nghiêm ngặt các loại cho các biến và chỉ cho phép một biến được gán các giá trị của cùng một "loại". Có một vài vấn đề với phương pháp này. Ví dụ, một chương trình có thể có một biến "yearOfBirth" là năm mà một người được sinh ra và thật hấp dẫn khi gõ nó thành một số nguyên ngắn. Tuy nhiên, nó không phải là một số nguyên ngắn. Năm nay, nó là một con số ít hơn năm 2009 và lớn hơn -10000. Tuy nhiên, bộ này tăng 1 mỗi năm khi chương trình chạy. Làm cho điều này là một "int ngắn" là không đủ. Điều cần thiết để làm cho loại biến an toàn này là chức năng xác thực thời gian chạy để đảm bảo rằng số này luôn lớn hơn -10000 và nhỏ hơn năm dương lịch tiếp theo.
Các ngôn ngữ sử dụng kiểu gõ động (hoặc gõ vịt hoặc gõ biểu hiện) như Perl, Python, Ruby, SQLite và Lua không có khái niệm về các biến được gõ. Điều này buộc lập trình viên phải viết một thói quen xác nhận thời gian chạy cho mọi biến để đảm bảo rằng nó là chính xác hoặc chịu đựng các hậu quả của các ngoại lệ thời gian chạy không giải thích được. Theo kinh nghiệm của tôi, các lập trình viên trong các ngôn ngữ được gõ tĩnh như C, C ++, Java và C # thường bị cho rằng các loại được xác định tĩnh là tất cả những gì họ cần làm để có được lợi ích của an toàn kiểu. Điều này chỉ đơn giản là không đúng với nhiều chương trình máy tính hữu ích và thật khó để dự đoán liệu nó có đúng với bất kỳ chương trình máy tính cụ thể nào không.
Dài và ngắn .... Bạn có muốn loại an toàn không? Nếu vậy, hãy viết các hàm thời gian chạy để đảm bảo rằng khi một biến được gán một giá trị, nó tuân thủ các tiêu chí được xác định rõ. Mặt trái là nó làm cho việc phân tích tên miền thực sự khó khăn đối với hầu hết các chương trình máy tính vì bạn phải xác định rõ ràng các tiêu chí cho từng biến chương trình.