Tôi thấy rằng có một số câu trả lời tốt. Một số trong đó tôi sẽ nhắc lại nhưng đôi khi bạn chỉ muốn đặt mọi thứ vào từ của riêng bạn. Tôi sẽ bình luận với một số ví dụ từ C ++ vì đó là ngôn ngữ mà tôi quen thuộc nhất.
Điều cần thiết là không bao giờ không khôn ngoan. Kiểu suy luận là cần thiết để làm cho các tính năng ngôn ngữ khác thực tế. Trong C ++ có thể có các loại không thể nhầm lẫn.
struct {
double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;
C ++ 11 thêm lambdas mà cũng không thể lộn xộn.
auto sq = [](int x) {
return x * x;
};
// there is no name for the type of sq
Gõ suy luận cũng là nền tảng cho các mẫu.
template <class x_t>
auto sq(x_t const& x)
{
return x * x;
}
// x_t is not known until it is inferred from an expression
sq(2); // x_t is int
sq(2.0); // x_t is double
Nhưng câu hỏi của bạn là "tại sao tôi, lập trình viên, muốn suy ra loại biến của tôi khi tôi đọc mã? Có phải mọi người chỉ đọc loại đó nhanh hơn là nghĩ loại nào không?"
Kiểu suy luận loại bỏ sự dư thừa. Khi nói đến việc đọc mã đôi khi có thể nhanh hơn và dễ dàng hơn để có thông tin dư thừa trong mã nhưng sự dư thừa có thể làm lu mờ thông tin hữu ích . Ví dụ:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
Không có nhiều sự quen thuộc với thư viện chuẩn cho một lập trình viên C ++ để xác định rằng tôi là một trình vòng lặp từ i = v.begin()
đó khai báo kiểu rõ ràng có giá trị giới hạn. Bằng sự hiện diện của nó, nó che khuất các chi tiết quan trọng hơn (chẳng hạn như chỉ ra i
điểm bắt đầu của vectơ). Câu trả lời hay của @amon cung cấp một ví dụ thậm chí tốt hơn về tính dài dòng làm lu mờ các chi tiết quan trọng. Ngược lại, sử dụng suy luận kiểu sẽ làm nổi bật hơn các chi tiết quan trọng.
std::vector<int> v;
auto i = v.begin();
Mặc dù đọc mã là quan trọng nhưng nó không đủ, đến một lúc nào đó bạn sẽ phải ngừng đọc và bắt đầu viết mã mới. Sự dư thừa trong mã làm cho việc sửa đổi mã chậm hơn và khó hơn. Ví dụ: giả sử tôi có đoạn mã sau:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
Trong trường hợp tôi cần thay đổi loại giá trị của vectơ để thay đổi mã thành:
std::vector<double> v;
std::vector<double>::iterator i = v.begin();
Trong trường hợp này tôi phải sửa đổi mã ở hai nơi. Tương phản với suy luận kiểu trong đó mã gốc là:
std::vector<int> v;
auto i = v.begin();
Và mã sửa đổi:
std::vector<double> v;
auto i = v.begin();
Lưu ý rằng bây giờ tôi chỉ phải thay đổi một dòng mã. Ngoại suy điều này thành một chương trình lớn và suy luận kiểu có thể truyền các thay đổi thành các loại nhanh hơn nhiều so với bạn có thể với một trình soạn thảo.
Sự dư thừa trong mã tạo ra khả năng lỗi. Bất cứ lúc nào mã của bạn phụ thuộc vào hai mẩu thông tin được giữ tương đương có khả năng xảy ra lỗi. Ví dụ, có một sự không nhất quán giữa hai loại trong tuyên bố này có lẽ không có ý định:
int pi = 3.14159;
Sự dư thừa làm cho ý định khó phân biệt hơn. Trong một số trường hợp, suy luận kiểu có thể dễ đọc và dễ hiểu hơn vì nó đơn giản hơn so với đặc tả kiểu rõ ràng. Hãy xem xét đoạn mã:
int y = sq(x);
Trong trường hợp sq(x)
trả về một int
, không rõ y
là int
vì nó là kiểu trả về sq(x)
hay vì nó phù hợp với các câu lệnh sử dụng y
. Nếu tôi thay đổi mã khác sao cho sq(x)
không còn trả về int
, thì không chắc chắn từ dòng đó có phải là loại y
cập nhật hay không. Tương phản với cùng một mã nhưng sử dụng kiểu suy luận:
auto y = sq(x);
Trong đó ý định là rõ ràng, y
phải cùng loại với trả về sq(x)
. Khi mã thay đổi loại trả về sq(x)
, loại y
thay đổi sẽ tự động khớp.
Trong C ++ có một lý do thứ hai tại sao ví dụ trên đơn giản hơn với suy luận kiểu, suy luận kiểu không thể đưa ra chuyển đổi kiểu ẩn. Nếu kiểu trả về sq(x)
là không int
, trình biên dịch sẽ âm thầm chèn một chuyển đổi ngầm định sang int
. Nếu kiểu trả về sq(x)
là loại phức tạp xác định operator int()
, lệnh gọi hàm ẩn này có thể phức tạp tùy ý.