Tại sao bạn phải chỉ định kiểu dữ liệu khi khai báo biến?


41

Trong hầu hết các ngôn ngữ mã hóa (nếu không phải tất cả), bạn cần khai báo các biến. Ví dụ trong C # nếu đó là trường số thì

int PhoneNumber

Nếu tôi đang sử dụng ngôn ngữ tiếng Anh bình thường, tôi không cần phải khai báo PhoneNumberintsử dụng nó. Ví dụ: nếu tôi nhờ bạn tôi Sam cho tôi số điện thoại của anh ấy, tôi nói:

"Sam cho tôi số điện thoại"

Tôi sẽ không nói

"Char (20) Sam đưa cho tôi số điện thoại int"

Tại sao chúng ta phải chỉ định loại dữ liệu?


83
Đó là bởi vì tiếng Anh có gõ ngầm - vì vậy yourPhoneNumber được ngầm gõ như một PhoneNumber - con người cũng có cấp phát bộ nhớ động ...;)
HorusKol

28
Bạn và Sam biết rằng một số điện thoại bao gồm các chữ số và bạn sẽ ngạc nhiên khi tìm thấy một chữ cái trong đó. Máy tính không và cần phải nói.
Thorbjørn Ravn Andersen

16
Và khi tôi nghe những con số như 1-800-JIMBO trong phim, suy nghĩ của tôi là: Con số đó như thế nào? Oo
muru

103
Bạn không nên khai báo số điện thoại là int. Trong hầu hết các ngôn ngữ lập trình, điều này sẽ xóa các số không hàng đầu.
Aron_dc

25
@HorusKol: con người không chỉ phân bổ bộ nhớ động mà còn là người thu gom rác không có ý thức cao ...
leftaroundabout

Câu trả lời:


79

Trong hầu hết các ngôn ngữ mã hóa (nếu không phải tất cả), bạn cần khai báo các biến.

[Càng]

Tại sao chúng ta phải chỉ định loại dữ liệu?

Đó là hai câu hỏi độc lập:

  • Tại sao chúng ta cần khai báo các biến?
  • Tại sao chúng ta cần khai báo các loại?

Ngẫu nhiên, câu trả lời cho cả hai là: chúng tôi không.

Có rất nhiều ngôn ngữ lập trình được nhập tĩnh mà bạn không cần phải khai báo các loại. Trình biên dịch có thể suy ra các loại từ bối cảnh xung quanh và cách sử dụng.

Ví dụ, trong Scala bạn có thể nói

val age: Int = 23

hoặc bạn chỉ có thể nói

val age = 23

Hai cái này hoàn toàn tương đương: trình biên dịch sẽ suy ra kiểu xuất phát Inttừ biểu thức khởi tạo 23.

Tương tự như vậy, trong C♯, bạn có thể nói một trong hai điều này và cả hai đều có nghĩa chính xác như nhau:

int age = 23;
var age = 23;

Tính năng này được gọi là suy luận kiểu và nhiều ngôn ngữ ngoài Scala và C♯ có nó: Haskell, Kotlin, Ceylon, ML, F♯, C ++, bạn đặt tên cho nó. Ngay cả Java cũng có các dạng suy luận kiểu hạn chế.

Trong các ngôn ngữ lập trình được gõ động, các biến thậm chí không có kiểu. Các loại chỉ tồn tại động khi chạy, không tĩnh. Chỉ các giá trị và biểu thức có loại và chỉ trong thời gian chạy, các biến không có loại.

Ví dụ: trong ECMAScript:

const age = 23;
let age = 23;

Và cuối cùng, trong rất nhiều ngôn ngữ, bạn thậm chí không cần phải khai báo các biến. ví dụ: trong Ruby:

age = 23

Trong thực tế, ví dụ cuối cùng đó là hợp lệ trong một số ngôn ngữ lập trình. Ví dụ, cùng một dòng mã cũng sẽ hoạt động trong Python.

Vì thế,

  • ngay cả trong các ngôn ngữ được nhập tĩnh nơi các biến có loại, bạn không nhất thiết phải khai báo chúng,
  • trong các ngôn ngữ được nhập động, các biến không có loại, vì vậy rõ ràng bạn thậm chí không thể khai báo chúng,
  • trong nhiều ngôn ngữ, bạn thậm chí không phải khai báo biến

2
Thêm một để giải thích cả suy luận kiểu và gõ động (ràng buộc muộn)
dcorking

36
Đây là thông tin tuyệt vời về những quan niệm sai lầm đằng sau câu hỏi, nhưng vẫn để lại câu hỏi chưa được trả lời. Câu hỏi, đúng hơn, là tại sao chúng ta phải chỉ định kiểu dữ liệu khi khai báo các biến trong các ngôn ngữ yêu cầu điều đó? Tại sao chúng được thiết kế theo cách? Có những câu trả lời hay cho câu hỏi đó, và trong khi xây dựng các giải pháp thay thế mở rộng tầm nhìn của OP và rất tốt, điều đó dường như không hoàn chỉnh đối với tôi.
KRyan

7
@KRyan: nếu bạn muốn biết lý do tại sao một nhà thiết kế ngôn ngữ nào đó đưa ra một lựa chọn thiết kế ngôn ngữ nhất định, bạn sẽ phải hỏi nhà thiết kế ngôn ngữ đó, tôi sợ. Tôi không thể cho bạn biết lý do tại sao các nhà thiết kế của C♯ quyết định chống lại suy luận kiểu, tôi cũng không thể cho bạn biết lý do tại sao sau đó họ đã thay đổi suy nghĩ của họ. Thiết kế ngôn ngữ được nhiều ý kiến ​​và thường đi xuống hương vị. Nếu, OTOH, bạn muốn biết về sự đánh đổi cụ thể có liên quan, thì câu trả lời về cơ bản sẽ là một bản in lại các loại và ngôn ngữ lập trình của giáo sư Pierce, quá rộng cho Stack Exchange.
Jörg W Mittag

2
JörgWMittag: như @KRyan đã nói, câu trả lời "bạn không cần phải" không thú vị lắm (nó rất rõ ràng - nhiều ngôn ngữ cho phép bỏ qua các khai báo loại trong một số trường hợp). Câu hỏi "tại sao bạn muốn khai báo các loại" thú vị hơn và phản ánh đúng hơn tinh thần của câu hỏi ban đầu (câu trả lời của bạn làm tôi nhớ đến câu nói đùa: "chúng ta đang ở đâu?" - "bạn đang ở trong khinh khí cầu ! " ). Bạn không cần phải biết một nhà thiết kế của một ngôn ngữ cụ thể nghĩ gì vào thời điểm đó, để cung cấp một số lý do chính đáng để ủng hộ khai báo kiểu.
jfs

1
@Zaibis : auto i = 1 // i is inferred to type int, vector<int> vec; auto itr = vec.iterator(); // itr is inferred to type vector<int>::iteratorvân vân. Nếu bạn muốn biết chính xác nó hoạt động như thế nào, bạn có thể tra cứu nó trong thông số kỹ thuật.
Jörg W Mittag

53

Khi bạn sử dụng ngôn ngữ tự nhiên để chỉ thông tin, nó không chính xác lắm và đặc biệt, không truyền đạt cho người khác nhiều về ý định của bạn. Những vấn đề tương tự xảy ra khi cố gắng làm toán bằng ngôn ngữ tự nhiên: nó không đủ chính xác.

Lập trình rất phức tạp; lỗi là tất cả quá dễ dàng để đi qua. Các loại là một phần của hệ thống kiểm tra được thiết kế để ngăn chặn các trạng thái chương trình bất hợp pháp, bằng cách phát hiện các điều kiện lỗi. Các ngôn ngữ khác nhau sử dụng các loại khác nhau: một số ngôn ngữ sử dụng nhiều loại để phát hiện lỗi tại thời điểm biên dịch. Hầu như tất cả các ngôn ngữ có một số khái niệm về các loại không tương thích là lỗi thời gian chạy. Thông thường một lỗi loại chỉ ra một lỗi nào đó trong chương trình. Khi chúng tôi cho phép các chương trình tiếp tục mặc dù có lỗi, chúng tôi có thể nhận được câu trả lời rất tệ. Chúng tôi muốn dừng chương trình hơn là nhận được câu trả lời xấu hoặc không chính xác.

Đặt một cách khác, các loại thể hiện ràng buộc về hành vi của chương trình. Các ràng buộc, khi được thực thi bởi một số cơ chế, cung cấp đảm bảo. Những đảm bảo như vậy giới hạn số lượng lý luận cần thiết để suy nghĩ về chương trình, do đó đơn giản hóa nhiệm vụ đọc và duy trì chương trình cho các lập trình viên. Không có các loại và hàm ý của các công cụ (tức là trình biên dịch) phát hiện lỗi loại, gánh nặng lập trình cao hơn đáng kể, và do đó, tốn kém hơn.

Đúng là (nhiều) con người dễ dàng phân biệt giữa một số điện thoại châu Âu, Hoa Kỳ và quốc tế. Tuy nhiên, máy tính không thực sự "nghĩ", và nếu được nói sẽ quay số điện thoại của các quốc gia thống nhất ở châu Âu hoặc ngược lại. Các loại, ví dụ, là một cách tốt để phân biệt giữa các trường hợp này, mà không cần phải dạy cho máy tính cách "suy nghĩ". Trong một số ngôn ngữ, chúng tôi có thể gặp lỗi biên dịch khi cố gắng trộn số điện thoại châu Âu trên hệ thống điện thoại của Mỹ. Lỗi đó cho chúng tôi biết rằng chúng tôi cần sửa đổi chương trình của mình (có lẽ bằng cách chuyển đổi số điện thoại thành chuỗi quay số quốc tế hoặc bằng cách sử dụng số điện thoại ở châu Âu thay thế), trước khi chúng tôi thậm chí cố gắng chạy chương trình.

Hơn nữa, như máy tính không nghĩ, tên của trường hoặc biến (ví dụ phonenumber), có nghĩa là không có gì với máy tính. Đối với máy tính, tên trường / biến đó chỉ là "blah123". Hãy suy nghĩ về chương trình của bạn sẽ như thế nào nếu tất cả các biến là "blahxxx". Rất tiếc. Vâng, đó là những gì máy tính nhìn thấy. Việc cung cấp một loại cho máy tính hiểu ý nghĩa của biến mà đơn giản là nó không thể suy ra từ tên của nó.

Hơn nữa, như @Robert nói, trong nhiều ngôn ngữ hiện đại, chúng ta không phải chỉ định các loại nhiều như ngày xưa, vì các ngôn ngữ như C # thực hiện "suy luận kiểu", là một bộ quy tắc để xác định loại phù hợp cho một biến trong bối cảnh. C # chỉ cung cấp suy luận kiểu trên các biến cục bộ, nhưng không cung cấp các tham số chính thức, hoặc các trường lớp hoặc thể hiện.


4
RE phần buồn: Không thể suy ra loại thành viên có thể truy cập công khai (trường công khai, chữ ký phương thức công khai), bởi vì bạn không thể dự đoán khi nào và làm thế nào nó sẽ được sử dụng. Ngoài ra, chú thích loại là tài liệu.
Sergio Tulentsev

Tôi nghĩ bạn nên làm nổi bật / in đậm dòng này: Types are part of a system of checks that ...vì nó trực tiếp trả lời OP trên Why do we have to specify data type at all?..
txtechhelp

Lưu ý: bạn trả lời giả định rằng một ngôn ngữ được sử dụng để chỉ định các loại bằng cách nào đó tốt hơn trong việc tránh lỗi so với ngôn ngữ lập trình thông thường của bạn. Rõ ràng là không phải vậy, ví dụ, hãy xem xét ngôn ngữ mẫu C ++ là Turing-Complete (và do đó cho phép thể hiện nhiều kiểm tra lỗi) nhưng hầu như không thể đọc được so với nhiều ngôn ngữ hoàn chỉnh Turing khác như Haskell, Python và thậm chí các phần khác của C ++ chính nó. Hãy tự hỏi tại sao bạn sẽ không sử dụng cùng một ngôn ngữ lập trình, để diễn đạt các kiểm tra lỗi như phần còn lại của chương trình của bạn (có một số câu trả lời tốt trong một số nhưng không phải tất cả các trường hợp).
jfs

@SergioTulentsev Điều đó không đúng - trong F #, bạn có thể có các phương thức công khai mà không chỉ định rõ ràng các loại của chúng. Trình biên dịch sẽ suy ra các kiểu từ việc sử dụng bên trong phương thức. Ví dụ: các định nghĩa phương thức công khai hợp lệ: static member add x y = x + y, member x.Append s = x.Text + s. Trong trường hợp đầu tiên, xysẽ được suy ra là ints vì sự bổ sung. Trong trường hợp thứ hai, chúng sẽ là bất cứ điều gì hợp lệ tùy thuộc vào loại x.Text- nếu đó là một string, thì scũng sẽ stringnhư vậy. Tôi đồng ý rằng các chú thích loại là tài liệu, mặc dù.
Roujo 22/03/2016

"Các kiểu cục bộ tiềm ẩn, các loại giao diện rõ ràng" là cách nhiều người lập trình, ngay cả trong các ngôn ngữ như Haskell cho phép bạn bỏ qua (gần) tất cả các loại trong khi vẫn có trình biên dịch suy ra các loại nghiêm ngặt. Có nhiều người không coi đó là điều đáng buồn khi một ngôn ngữ thực thi cách làm này (như C # hiện).
Ben

29

Ngoài các câu trả lời khác, có một điều cần được đưa vào. Hãy nhớ rằng máy tính chỉ là bit. Nói rằng tôi cung cấp cho bạn các byte:

26 3A 00 FF

Điều đó có nghĩa là gì? Nó được máy tính lưu trữ theo cách này, nhưng không có bất kỳ sự giải thích nào, nó chỉ là bit . Nó có thể là 4 nhân vật ascii. Nó có thể là một số nguyên. Nó có thể là một số byte trong một mảng. Nó có thể là một phần của một đối tượng. Nó có thể là một con trỏ tới nơi mà video mèo đang đệm. Khá nhiều tất cả các ngôn ngữ lập trình từ lắp ráp trở lên cần một cái gì đó để biết cách diễn giải các bit để làm cho chúng thực hiện tính toán có ý nghĩa.

Và vì máy tính không thể biết ý nghĩa của các bit đó, nên nó cần bạn nói với nó - rõ ràng thông qua các chú thích kiểu, hoặc ngầm thông qua các cơ chế suy luận kiểu được đề cập trong các câu trả lời khác.


10
Đúng như vậy, nhưng để thực sự làm hỏng tâm trí của bạn, nhận ra rằng máy tính không bao giờ có khả năng hiểu những bit đó có nghĩa là gì ngay cả khi bạn nói với nó nhiều chú thích kiểu hơn. Giải thích của bạn chỉ được chuyển thành số hex nhiều hơn, để "làm rõ" các số hex đầu tiên. Điều quan trọng là tất cả được tạo ra bởi mọi người để đưa ý định vào thiết bị điện tử và khiến họ thực hiện những gì chúng tôi dự định. Bây giờ hãy nói "cảm ơn" với một kỹ sư. :)
tự đại diện

1
Tôi đã dành nhiều năm lập trình trên máy tính lớn. Với PL / 1 câu trả lời này có ý nghĩa rất nhiều. Thường xuyên, chúng tôi sẽ được sử dụng lưu trữ dựa trên một con trỏ được đặt thành địa chỉ của một biến khác có kiểu dữ liệu khác để truy cập các byte theo một cách khác. Ví dụ: PL / 1 không hỗ trợ trường số nhị phân 1 byte, nhưng chúng tôi sẽ dựa vào biến 1 ký tự tại địa chỉ để cho phép chúng tôi lưu trữ một mảng 6 byte lưu trữ 6 trường nhị phân một byte (trong trường hợp này cho phép chúng tôi lưu 6 byte cho mỗi địa chỉ - rất quan trọng khi lưu trữ đắt tiền).
Khởi động

1
Máy tính có thể hiểu rất nhiều khả năng nhưng ngay cả các trình biên dịch thông minh cũng cần bối cảnh để hiểu. Nó không giống với số 0 hoặc "0". Hoặc Chuỗi "Ngày 31 tháng 12" sẽ được đặt hàng trước "Ngày 1 tháng 5" được coi là Chuỗi nhưng không được coi là Ngày. Hoặc mất 5/2. Nó là 2 khi nhập nhưng 2,5 là gấp đôi. Ngoài ra, loại là một biện pháp bảo mật chống lại các chuyển đổi không mong muốn. Null, NaN, và làm tròn hoặc tràn cũng có thể trở thành một vấn đề. Ngôn ngữ gõ mạnh và tĩnh có một số lợi thế. Ví dụ, trình biên dịch giúp bạn phát hiện các vấn đề trong khi tái cấu trúc.
Borjab

1
@Borjab Ý của bạn là "Nó là 2 như một số nguyên "?
Richard Everett

1
@RichardEverett Chắc chắn đó là một vòng. Cảm ơn nhưng đến muộn để chỉnh sửa nó.
Borjab

23

Câu trả lời cho lý do tại sao các máy tính cần thông tin này phải liên quan đến Biểu diễn dữ liệu .

Tên của "kiểu dữ liệu" là một tham chiếu đến các quy tắc giúp máy tính lưu trữ và truy xuất thông tin từ trạng thái thô là 0 và 1 trong bộ nhớ máy tính.

Ví dụ: ký tự ASCII 8 bit thông thường của bạn sẽ được lưu trong bộ nhớ máy tính (RAM hoặc Đĩa) dưới dạng 01000001(ký tự viết hoa "A", mã ASCII 65) hoặc 00001000(ký hiệu phần trăm) hoặc bất kỳ kết hợp nào của 0 và 1 trong 8 bit đó.

Đối với một ví dụ khác, một số nguyên không dấu 8 bit có thể được lưu trữ dưới dạng 00000101(số 5) hoặc 00001000(số 8)

Lưu ý cách biểu diễn nhị phân của 8 và ký tự% có thể giống nhau, nhưng chúng có nghĩa là những thứ khác nhau vì kiểu của chúng khác nhau.

Ngay cả các ngôn ngữ suy ra kiểu dữ liệu, chúng có thể không có quy tắc rằng "tất cả các kiểu của varibles phải được khai báo bởi người lập trình", chúng có các quy tắc như "nếu chuỗi ký tự của bạn được đặt trong dấu ngoặc kép, thì đó là một chuỗi" và nhiều quy tắc hơn cho mỗi loại dữ liệu.

Vì vậy, ngay cả những loại này cũng cần các kiểu dữ liệu để hiểu ý nghĩa của 0 và 1, vì vậy chúng có thể thực hiện chức năng nối chuỗi nếu bạn cố gắng "thêm" hai ký tự hoặc thêm số nguyên nếu bạn đang cố thêm hai số nguyên .

Trong câu chuyện của bạn cũng vậy, giả sử bạn không hỏi Sam số điện thoại nhưng Sam đưa cho bạn một mảnh giấy có "1123581321" được viết trên đó. Bạn không thể chắc chắn nếu Sam chỉ là một fan hâm mộ của tám số Fibonacci đầu tiên, hoặc nếu đó là số điện thoại. Để đoán, bạn sẽ phải tính đến bối cảnh và tín hiệu bạn có sẵn, như có lẽ bạn đã hỏi Sam số điện thoại một ngày trước, hoặc ghi chú ghi "Gọi cho tôi" hoặc nếu bạn đếm các chữ số và tìm nó phù hợp với mô hình của hầu hết các số điện thoại. Chỉ sau đó bạn mới biết rằng đó là số điện thoại mà bạn có thể gọi chứ không phải một số chữ số mà bạn bấm vào máy tính.

Lưu ý cách các gợi ý này đưa bạn đến dự đoán rằng số đó là số điện thoại tương tự như cách gợi ý dẫn ngôn ngữ máy tính không yêu cầu khai báo để suy ra loại giá trị.


3
Đây là câu trả lời gần nhất. Tất cả phải làm với bộ nhớ. Bạn khai báo kiểu để trình biên dịch biết cần bao nhiêu bộ nhớ cho ứng dụng khi chạy. Biết làm thế nào các bit nên được giải thích là thứ yếu.
Greg Burghardt

@GregBurghardt đúng. Để hiểu được các bit đã có mặt cũng như đặt các bit ở vị trí đầu tiên sau khi chuyển đổi dữ liệu đã cho thành nhị phân theo loại dữ liệu.
Peeyush Kushwaha

10

Trong một số ngôn ngữ, bạn không phải chỉ định loại dữ liệu.

Các ngôn ngữ hỗ trợ suy luận kiểu thường có thể tìm ra kiểu dữ liệu từ việc sử dụng của bạn. Ví dụ,

var name = "Ali"

được gõ bên trong dưới dạng một chuỗi, bởi vì giá trị được bao quanh bởi dấu ngoặc kép.

Một số ngôn ngữ không yêu cầu bạn khai báo biến; biến được tạo khi nó được sử dụng lần đầu tiên. Tuy nhiên, nó được coi là một cách thực hành tốt nhất để khai báo cụ thể các biến của bạn, vì một số lý do quan trọng; chủ yếu là vì làm như vậy tốt hơn thể hiện ý định của bạn.


5
Các var name = "Ali"phong cách thực sự phổ biến đối với hiện đại tĩnh ngôn ngữ gõ. Trong các ngôn ngữ gõ tĩnh, loại được cố định khi tạo, nhưng nó vẫn có thể được xác định bởi trình khởi tạo. Định nghĩa của một ngôn ngữ được gõ động là các kiểu gắn với các giá trị, không phải các biến. Việc gán giá trị cho một biến do đó cũng đặt loại của biến.
MSalters

@MSalters: Tôi đã điều chỉnh một chút về từ ngữ.
Robert Harvey

5
Điều trớ trêu ở đây là điều này bao gồm C # với cú pháp chính xác này.
Derek Elkins

1
@MSalters Gán một giá trị cho một biến do đó cũng đặt loại của biến. Hoặc là biến không có kiểu vốn có và trình thông dịch sẽ cố gắng áp dụng bất kỳ thao tác nào cho giá trị của biến. Có bất kỳ ngôn ngữ được nhập động nào mà mã như sau (Javascript) sẽ không được phép var x = 5; x = "";vì câu lệnh đầu tiên gây ra xloại "Số" được liên kết xkhông? Sắp xếp các xung đột với kiểu gõ động . Và nếu không, loại liên quan đến biến có ảnh hưởng gì, ngoài liên kết loại với giá trị?
Zev Spitz

1
@ZevSpitz: Loại hệ thống đầu tiên không được gõ động, nhưng hoàn toàn không được gõ. Ví dụ Javascript của bạn không được nhập động, chính xác vì loại Số không thể thay đổi. Trong một ngôn ngữ được gõ động, x = "";thay đổi loại x thành chuỗi, ngay cả khi đó là một số trước đó.
MSalters

9

Bởi vì đó là những gì thiết kế ngôn ngữ chỉ định. Vì vậy, để trả lời câu hỏi của bạn, chúng ta cần xem xét ý định đằng sau việc gõ rõ ràng trong các ngôn ngữ như C # và C ++. (Chà, C # làm điều đó bởi vì C ++ làm điều đó bởi vì C làm điều đó, vì vậy chúng ta cần xem xét ý định trở lại sau đó).

Đầu tiên, gõ rõ ràng và gõ tĩnh cung cấp sự nghiêm ngặt trong mã hóa - chỉ định một biến là một số nguyên có nghĩa là trình biên dịch và phần mềm sẽ bị bất ngờ và đưa ra lỗi khi bạn gán một ký tự hoặc chuỗi cho biến. Gõ động có thể gây đau đầu cho người không thận trọng (chỉ cần nhìn vào cách tiếp cận PHP hoặc javascripts về tính trung thực của những thứ như mảng và chuỗi rỗng).

Bạn có thể có động tĩnh với kiểu gõ ngầm - khởi tạo một biến thành một chuỗi có nghĩa là biến đó chỉ nên là một chuỗi, nhưng cảm giác của tôi là điều này có thể gây ra vấn đề cho con người khi đọc mã (Tôi có xu hướng giả định gõ động khi có gõ ngầm ).

Ngoài ra, trong một số ngôn ngữ, có thể viết một cái gì đó giống như mã giả này để khởi tạo một lớp từ đầu vào chuỗi:

PhoneNumber phoneNumber = "(61) 8 8000 8123";

Thứ hai, gõ rõ ràng cũng đi đôi với phân bổ bộ nhớ. Một int luôn có rất nhiều byte. Một PhoneNumber có rất nhiều byte. Trình biên dịch có thể gán một khối bộ nhớ có kích thước phù hợp mà sau đó có thể được sử dụng mà không cần phải xem nó cần bao nhiêu dung lượng khi bạn gán giá trị.

PhoneNumber phoneNumber;
...
phoneNumber = "some value from somewhere";

Cuối cùng, nó loại bỏ sự nhầm lẫn ... là 123 một số nguyên hay một số nguyên không dấu? Chúng cần cùng số byte, nhưng giá trị tối đa được lưu trữ trong các biến của một trong hai loại rất khác nhau ...

Điều này không có nghĩa là rõ ràng tốt hơn ẩn - nhưng thiết kế ngôn ngữ dựa trên các loại lựa chọn này và C # sẽ hoạt động khác với cách gõ ngầm. PHP và javascript sẽ hoạt động khác nhau với cách gõ rõ ràng.


5

Bởi vì Sam thông minh hơn trình biên dịch. Chẳng hạn, khi bạn nói hãy cho tôi số điện thoại, bạn không chỉ định xem bạn muốn tiền tố quốc gia hay mã vùng cho dù đó là số công việc chỉ yêu cầu 4 chữ số cuối. Ngoài ra, nếu bạn hỏi số lượng khớp pizza địa phương, bạn sẽ có thể đối phó với câu trả lời "pizza4u".

Sam, tìm ra nó từ bối cảnh. Mặc dù trình biên dịch cũng có thể tìm ra nó từ ngữ cảnh, Sam sẽ giỏi hơn về nó (và có khả năng làm gián đoạn quá trình để yêu cầu làm rõ).

Có hai cách tiếp cận cơ bản đối với loại và biến, hoặc biến có loại, trong trường hợp đó, các hành động không được loại đó cho phép bị cấm và ngăn chặn biên dịch hoặc giá trị có loại và hành động không được phép loại được bắt tại thời gian chạy.

Mỗi phương pháp đều có ưu điểm và nhược điểm của nó. Nói chung, các nhà văn biên dịch cố gắng giảm thiểu những nhược điểm và tối đa hóa các lợi thế. Đó là lý do tại sao C # cho phép var phoneNumber = GetPhoneNumber();và sẽ suy ra loại số điện thoại từ chữ ký của GetPhoneNumber. Điều đó có nghĩa là bạn phải khai báo kiểu cho phương thức, nhưng không phải là biến nhận kết quả. Mặt khác, có nhiều loại dự án gợi ý / thực thi cho javascript. Mọi thứ đều là sự đánh đổi.


3

Đó là vấn đề về cách lưu trữ dữ liệu. Sự tương tác của bạn với Sam sẽ làm cho một so sánh tốt hơn nếu bạn hỏi để bạn có thể viết nó xuống nhưng chỉ có giấy có giá trị tám ký tự.

"Sam, cho tôi số điện thoại."

"5555555555"

"Ồ không, tôi hết giấy. Nếu tôi biết trước được bao nhiêu dữ liệu tôi yêu cầu thì tôi có thể chuẩn bị tốt hơn!"

Vì vậy, thay vào đó, hầu hết các ngôn ngữ làm cho bạn khai báo một loại, vì vậy nó sẽ biết và chuẩn bị trước thời hạn:

"Sam, số điện thoại là bao lâu?"

"Mười nhân vật."

"Ok, sau đó hãy để tôi lấy một tờ giấy lớn hơn. Bây giờ hãy đưa cho tôi số điện thoại."

"5555555555"

"Hiểu rồi! Cảm ơn Sam!"

Nó thậm chí còn hairier khi bạn nhìn vào những cách cơ bản thực tế mà dữ liệu được lưu trữ. Nếu bạn giống tôi, bạn có một cuốn sổ ghi chú linh tinh, những con số được viết nguệch ngoạc, không có ngữ cảnh hay ghi nhãn cho bất cứ điều gì và bạn không biết bất kỳ ý nghĩa nào trong ba ngày sau đó. Đây là một vấn đề cho máy tính rất nhiều lần, quá. Rất nhiều ngôn ngữ có loại "int" (int, long, short, byte) và "float" (float, double). Tại sao điều đó là cần thiết?

Đầu tiên, hãy xem cách một số nguyên được lưu trữ và thường được biểu diễn trong máy tính. Bạn có thể biết rằng ở cấp độ cơ bản, tất cả đều là nhị phân (1 và 0). Nhị phân thực sự là một hệ thống số hoạt động chính xác như hệ thống số thập phân của chúng tôi. Trong phần thập phân, bạn đếm từ 0 đến 9 (với các số 0 đứng đầu vô hạn mà bạn không viết), sau đó bạn quay lại 0 và tăng chữ số tiếp theo để bạn có 10. Bạn lặp lại cho đến khi bạn cuộn từ 19 đến 20, lặp lại cho đến khi bạn cuộn từ 99 đến 100, và cứ thế.

Nhị phân không khác nhau, ngoại trừ thay vì 0 đến 9, bạn đếm 0 đến 1. 0, 1, 10, 11, 100, 101, 110, 111, 1000. Vì vậy, khi bạn nhập 9, trong bộ nhớ được ghi ở dạng nhị phân là 1001. Đây là một con số thực tế. Nó có thể được thêm, trừ, nhân, v.v., dưới dạng chính xác. 10 + 1 = 11. 10 + 10 = 100 (cuộn từ 1 đến 0 và mang theo 1). 11 x 10 = 110 (và tương đương, 11 + 11 = 110).

Bây giờ trong bộ nhớ thực (bao gồm các thanh ghi), có một danh sách, mảng, bất cứ thứ gì bạn muốn gọi nó, của các bit (tiềm năng 1 hoặc 0 ') ngay cạnh nhau, đó là cách nó giữ các bit này được tổ chức hợp lý để tạo ra một số lớn hơn 1. Vấn đề là, bạn sẽ làm gì với số thập phân? Bạn không thể chỉ chèn một phần cứng vào giữa hai bit trong thanh ghi và sẽ tốn quá nhiều chi phí để thêm "bit thập phân" vào giữa mỗi cặp bit. Vậy lam gi?

Bạn mã hóa nó. Nói chung, kiến ​​trúc của CPU hoặc phần mềm sẽ xác định cách thực hiện, nhưng một cách phổ biến là lưu trữ một dấu (+ hoặc -, nói chung là 1 âm) trong bit đầu tiên của thanh ghi, một mantissa (số của bạn đã thay đổi tuy nhiên nhiều lần cần phải loại bỏ số thập phân) cho số bit X sau đây và số mũ (số lần bạn phải thay đổi nó) cho phần còn lại. Nó tương tự như ký hiệu khoa học.

Gõ cho phép trình biên dịch biết những gì nó đang nhìn. Hãy tưởng tượng rằng bạn đã lưu trữ giá trị 1.3 trong thanh ghi 1. Chúng ta sẽ đưa ra sơ đồ mã hóa ưa thích của riêng mình ở đây, 1 bit cho ký hiệu, 4 ​​cho mantissa, 3 cho số mũ (1 bit cho ký hiệu, 2 cho cường độ). Đây là một số dương, vì vậy dấu là dương (0). Mantissa của chúng tôi sẽ là 13 (1101) và số mũ của chúng tôi sẽ là -1 (101 (1 cho âm, 01 = 1)). Vì vậy, chúng tôi lưu trữ 01101101 trong đăng ký 1. Bây giờ chúng tôi đã không nhập biến này, vì vậy khi thời gian chạy sử dụng nó, nó nói "chắc chắn, đây là số nguyên tại sao không" vì vậy khi in giá trị chúng tôi thấy 109 (64 + 32 + 8 + 4 + 1), điều này rõ ràng là không đúng.

Tuy nhiên, không phải ngôn ngữ nào cũng yêu cầu bạn gõ một cách rõ ràng. C # có từ khóa "var" khiến loại biến được giải thích tại thời điểm biên dịch và các ngôn ngữ khác như Javascript được nhập hoàn toàn tự động, đến mức bạn có thể lưu trữ một số nguyên trong một biến, sau đó gán nó cho boolean, sau đó gán nó cho boolean gán lại cho một chuỗi và ngôn ngữ theo dõi tất cả.

Nhưng trình biên dịch, trình thông dịch hoặc thời gian chạy dễ dàng hơn nhiều - và thường dẫn đến một chương trình nhanh hơn vì nó không phải tiêu tốn tài nguyên có giá trị sắp xếp thông qua việc gõ mọi thứ - để hỏi bạn, lập trình viên, loại nào dữ liệu bạn đang cung cấp cho nó.


2

Có những ngôn ngữ lập trình mà bạn không phải khai báo các kiểu dữ liệu cho các biến của mình. Thậm chí có những ngôn ngữ lập trình mà bạn không phải khai báo các biến trước đó; bạn có thể sử dụng chúng ngay lập tức

Rắc rối với việc không khai báo tên biến là nếu bạn vô tình viết sai tên của một biến, giờ đây bạn đã vô tình tạo ra một biến mới, hoàn toàn không liên quan. Vì vậy, khi bạn chạy chương trình của mình, bạn không thể hiểu tại sao cái biến mà bạn thiết lập đột nhiên không có gì trong đó ... Cho đến khi, sau nhiều giờ gỡ lỗi, bạn nhận ra mình đã gõ sai tên chết tiệt! GRRR !!

Vì vậy, họ đã tạo ra nó để bạn phải khai báo tên biến bạn sẽ sử dụng trước. Và bây giờ khi bạn gõ sai tên, bạn sẽ gặp lỗi thời gian biên dịch, nó sẽ ngay lập tức cho bạn biết chính xác lỗi đó ở đâu, trước khi chương trình của bạn chạy. Điều đó có dễ dàng hơn nhiều không?

Đối phó với các loại dữ liệu. Có những ngôn ngữ lập trình mà bạn không phải khai báo những thứ nên là loại. Nếu bạn có một customerbiến thực sự chỉ là tên của khách hàng, không phải toàn bộ đối tượng khách hàng, cố gắng lấy địa chỉ khách hàng từ một chuỗi thông thường ... sẽ không hoạt động. Toàn bộ điểm của kiểu gõ tĩnh là chương trình sẽ không biên dịch; nó sẽ lớn tiếng phàn nàn, chỉ ra chính xác nơi xảy ra sự cố. Đó là nhiều nhanh hơn chạy mã của bạn và cố gắng tìm ra lý do tại sao các địa ngục nó không làm việc.

Tất cả đều là các tính năng để cho trình biên dịch biết bạn dự định làm gì, vì vậy nó có thể kiểm tra những gì bạn thực sự đã làm và đảm bảo nó có ý nghĩa. Điều đó giúp trình biên dịch có thể tự động xác định vị trí lỗi cho bạn, đó là một Thỏa thuận lớn.

(Quay về quá khứ xa xôi, bạn không phải khai báo chương trình con . Bạn sẽ chỉ GOSUBđến một số dòng cụ thể. Nếu bạn muốn truyền thông tin giữa các chương trình con, bạn sẽ đặt các biến toàn cục cụ thể, gọi chương trình con của bạn, rồi kiểm tra khác biến khi chương trình con trở lại. Nhưng điều đó làm cho việc quên một cách tham số trở nên dễ dàng đến mức đáng sợ . Vì vậy, bây giờ hầu như tất cả các ngôn ngữ lập trình hiện đại đều yêu cầu bạn khai báo các tham số thực tế mà chương trình con lấy, vì vậy chúng tôi có thể kiểm tra xem bạn đã chỉ định tất cả chúng chưa. )


1
Trong C ++, bạn có thể đặt "auto x = 1" và nó biết đó là số nguyên. tự động y = 1,2; tự động z = 'Z'; vv
QuentinUK

@QuentinUK Trong C #, bạn có thể đặt var x=1kết quả tương tự. Nhưng đó không là gì cả; trong Haskell, bạn có thể viết toàn bộ chương trình của bạn không có loại chữ ký ở tất cả, nhưng nó là tất cả tĩnh đánh máy, và bạn vẫn nhận được lỗi nếu bạn thực hiện một sai lầm ... (Không chính xác chính mặc dù.)
MathematicalOrchid

@QuentinUK Nhưng nếu bạn viết kẻ nói dối for (auto i=0; i<SomeStdVector.size(); ++i)của bạn sẽ phàn nàn vì nó đã suy ra một loại đã ký và bạn tiến hành so sánh nó với một loại không dấu. Bạn phải viết auto i=0ul(đưa thông tin loại một cách rõ ràng một lần nữa, vì vậy chỉ nên viết size_t i=0ở vị trí đầu tiên).
dmckee

1

Nếu tôi đang sử dụng ngôn ngữ tiếng Anh bình thường, tôi không cần khai báo PhoneNumber là int để sử dụng ngôn ngữ đó. Ví dụ: nếu tôi nhờ bạn tôi Sam cho tôi số điện thoại của anh ấy, tôi nói:

"Sam cho tôi số điện thoại"

Tôi sẽ không nói>

"Char (20) Sam đưa cho tôi số điện thoại int"

Tại sao chúng ta phải chỉ định loại dữ liệu?

Lướt qua MathOverflow hoặc Khoa học máy tính lý thuyết và đọc một lúc để có ý tưởng về cách con người giao tiếp với nhau khi họ muốn đảm bảo rằng không có khả năng hiểu lầm. Hoặc đọc tiêu chuẩn cho một số ngôn ngữ lập trình trưởng thành.

Bạn sẽ thấy rằng việc xác định loại giá trị nào được phép cho một thuật ngữ một phần của thực hành giao tiếp thực sự chính xác ngay cả giữa người với người.

Điều bạn nhận thấy là các tương tác hàng ngày khá thường xuyên và con người khá dễ chịu lỗi, do đó, sự hiểu lầm về số điện thoại thường được tránh bởi kiến ​​thức chia sẻ của những người tham gia.

Nhưng bạn đã bao giờ thử lấy số điện thoại của một người ở nước khác chưa? Có phải họ đã nói với bạn một cách rõ ràng bao nhiêu lần để đẩy số không để đến địa chỉ quốc tế? Họ đã cho bạn biết mã quốc gia của họ? Bạn có nhận ra nó là như vậy? Bạn mong đợi bao nhiêu chữ số? Bạn đã nhận được bao nhiêu Bạn có biết làm thế nào để nhóm các chữ số? Hoặc thậm chí nếu nhóm có ý nghĩa?

Đột nhiên, vấn đề khó khăn hơn rất nhiều và có lẽ bạn đã cẩn thận hơn rất nhiều để kiểm tra một cách rõ ràng rằng con số nhận được có được hiểu theo cách người gửi muốn nói hay không.


0

Một lý do khác để khai báo các loại là hiệu quả. Mặc dù một số nguyên có thể được lưu trữ trong 1 byte hoặc 2 byte hoặc 4, một chương trình sử dụng số lượng biến rất lớn có thể sử dụng gấp 4 lần bộ nhớ cần thiết, tùy thuộc vào những gì được thực hiện. Chỉ lập trình viên biết nếu một không gian lưu trữ nhỏ hơn là khả thi, vì vậy anh ta có thể nói như vậy bằng cách khai báo loại.

Ngoài ra, các đối tượng gõ động cho phép nhiều loại có thể, trên đường bay. Điều đó có thể phải chịu một số chi phí "dưới mui xe", làm chậm chương trình so với việc gắn bó với một loại tất cả cùng.


0

Một số ngôn ngữ lập trình ban đầu (đặc biệt là Fortran) không yêu cầu bạn khai báo các biến trước khi sử dụng.

Điều này dẫn đến một số vấn đề. Một điều thực sự rõ ràng là trình biên dịch không còn có thể mắc các lỗi đánh máy đơn giản gần như đáng tin cậy. Nếu bạn có mã được cho là để sửa đổi một biến hiện có, nhưng có lỗi đánh máy, bạn vẫn có mã hoàn toàn hợp pháp vừa tạo (và gán giá trị cho) một biến mới:

longVariableName = 1

// ...

longVaraibleName = longvariableName + anotherLongVariableName

Bây giờ, xem xét vấn đề này một cách cô lập, với việc tôi đã đề cập đến một lỗi đánh máy là nguồn gốc của vấn đề, có lẽ khá dễ dàng để tìm ra lỗi đánh máy và vấn đề ở đây. Trong một chương trình dài, nơi mã này được chôn ở giữa rất nhiều mã khác, việc bỏ lỡ sẽ dễ dàng hơn rất nhiều.

Ngay cả hiện tại với nhiều ngôn ngữ được gõ động, bạn vẫn có thể gặp vấn đề cơ bản tương tự khá dễ dàng. Một số có một số phương tiện để cảnh báo bạn nếu bạn gán cho một biến, nhưng không bao giờ đọc nó (điều này theo kinh nghiệm bắt gặp khá nhiều vấn đề như thế này) cả hai đều không có những thứ như vậy.


0

Khi bạn khai báo bất kỳ biến nào, một số không gian được phân bổ trong bộ nhớ ,, nhưng máy (máy tính trong trường hợp này) không biết rằng phải phân bổ bao nhiêu dung lượng cho biến đó.

Ví dụ: - bạn tạo một chương trình yêu cầu người dùng nhập bất kỳ số nào, trong trường hợp này bạn phải chỉ định một kiểu dữ liệu để lưu trữ số đó, nếu không, máy không thể tự đánh giá rằng nó nên phân bổ 2 byte hoặc 2 gigabyte , nếu nó cố gắng để tự phân bổ thì nó có thể dẫn đến việc sử dụng bộ nhớ không hiệu quả .. Mặt khác, nếu bạn chỉ định kiểu dữ liệu trong chương trình của mình, thì sau khi biên dịch, máy sẽ phân bổ không gian phù hợp theo nhu cầu.


điều này dường như không cung cấp bất cứ điều gì đáng kể qua các điểm được thực hiện và giải thích trong 11 câu trả lời trước
gnat

1
Gnat bạn nên đọc lại tất cả các câu trả lời một cách kỹ lưỡng và thấy rằng tôi đã cố gắng trả lời câu hỏi này theo cách đơn giản hơn nhiều mà người ta có thể dễ dàng hiểu được.
Atul170294

Tôi vừa kiểm tra lại ba câu trả lời gần đây nhất được đăng khoảng một giờ trước câu trả lời này và cả ba câu hỏi dường như đều có cùng quan điểm và mỗi bài đọc của tôi giải thích nó theo cách đơn giản hơn ở đây
gnat

Mặc dù tôi đã không trả lời cho phần thưởng của phiếu bầu của bạn nhưng tôi nghĩ bạn nên biết một điều ,, bạn nên hạ thấp câu trả lời vì nó có thể cung cấp thông tin vô ích hoặc sai và nếu nó có bất cứ điều gì gây khó chịu. Tất cả các câu trả lời có thông tin hữu ích và phù hợp nhất sẽ nhận được số lượng upvote cao hơn, đủ để phân biệt giữa một câu trả lời, một câu trả lời tốt và câu trả lời tốt nhất. Hoạt động trẻ con của bạn về việc hạ thấp một câu trả lời mà không có bất kỳ lý do mạnh mẽ nào sẽ chỉ làm nản lòng những người khác cũng muốn chia sẻ ý kiến ​​của họ mà họ cho rằng có thể hữu ích cho người khác
Atul170294

1
Câu trả lời của bạn rất có thể bị bỏ qua vì nó không đúng. Gõ tĩnh không cần thiết để giúp quản lý bộ nhớ. Có nhiều ngôn ngữ cho phép gõ động và những ngôn ngữ / môi trường đó có thể xử lý các vấn đề quản lý bộ nhớ mà bạn đề cập.
Jay Elston
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.