Tại sao khai báo các biến gần với nơi chúng được sử dụng?


10

Tôi đã nghe mọi người nói rằng các biến nên được khai báo càng gần với cách sử dụng của họ càng tốt. Tôi không hiểu điều này.

Ví dụ: chính sách này sẽ đề nghị tôi nên làm điều này:

foreach (var item in veryLongList) {
  int whereShouldIBeDeclared = item.Id;
  //...
}

Nhưng chắc chắn điều này có nghĩa là chi phí tạo ra một cái mới intđược phát sinh trên mỗi lần lặp. Sẽ không tốt hơn để sử dụng:

int whereShouldIBeDeclared;
foreach (var item in veryLongList) {
  whereShouldIBeDeclared = item.Id;
  //...
}

Xin ai đó có thể giải thích?


3
Nó sẽ là một ngôn ngữ nghèo nàn chết tiệt mà đối xử với hai trường hợp khác nhau.
Paul Tomblin

5
Bạn bắt đầu từ một tiền đề sai. Vui lòng xem câu trả lời của tôi cho câu hỏi này: stackoverflow.com/questions/6919655/
Kẻ

8
Nếu bạn nghĩ như vậy, bạn không phù hợp để tối ưu hóa hoặc thậm chí xem xét các tác động hiệu suất nói chung. Việc triển khai ngôn ngữ rất thông minh và nếu bạn nghĩ rằng chúng không có, hãy chứng minh điều đó bằng dữ liệu cứng thu được thông qua các điểm chuẩn thực tế, không thiên vị.

4
Nếu hai ví dụ mã có sự khác biệt đáng kể về ngữ nghĩa, thì chúng sẽ làm những việc khác nhau. Bạn nên sử dụng một trong đó làm những gì bạn muốn làm. Quy tắc về nơi bạn khai báo các biến chỉ áp dụng cho các trường hợp không tạo ra sự khác biệt về ngữ nghĩa.
David Schwartz

4
Xem xét kết thúc ngược lại của quy mô - tất cả mọi thứ là một biến toàn cầu. Chắc chắn 'tuyên bố gần sử dụng' là kết thúc tốt hơn của phổ này?
JBRWilkinson

Câu trả lời:


27

Đây là một quy tắc phong cách giữa nhiều người và nó không nhất thiết là quy tắc quan trọng nhất trong tất cả các quy tắc có thể bạn có thể xem xét. Ví dụ của bạn, vì nó bao gồm một int, không phải là siêu hấp dẫn, nhưng bạn chắc chắn có thể có một đối tượng đắt tiền để xây dựng bên trong vòng lặp đó, và có lẽ là một đối số tốt để xây dựng đối tượng bên ngoài vòng lặp. Tuy nhiên, điều đó không làm cho nó trở thành một lý lẽ tốt để chống lại quy tắc này kể từ đầu tiên, có rất nhiều nơi khác có thể áp dụng mà không liên quan đến việc xây dựng các đối tượng đắt tiền trong một vòng lặp, và thứ hai, một trình tối ưu hóa tốt (và bạn đã gắn thẻ C #, vì vậy bạn có một trình tối ưu hóa tốt) có thể kéo việc khởi tạo ra khỏi vòng lặp.

Lý do thực sự cho quy tắc này cũng là lý do bạn không thấy lý do tại sao đó là quy tắc. Mọi người thường viết các hàm dài hàng trăm, thậm chí hàng nghìn dòng và họ thường viết chúng trong các trình soạn thảo văn bản thuần túy (nghĩ là Notepad) mà không có loại hỗ trợ Visual Studio cung cấp. Trong môi trường đó, việc khai báo một biến cách xa hàng trăm dòng từ nơi nó được sử dụng có nghĩa là người đang đọc

if (flag) limit += factor;

không có nhiều manh mối về cờ, giới hạn và yếu tố là gì. Các quy ước đặt tên như ký hiệu Hungary đã được thông qua để trợ giúp điều này, và các quy tắc như tuyên bố những thứ gần với nơi chúng được sử dụng cũng vậy. Tất nhiên, ngày nay, tất cả chỉ là về tái cấu trúc và các chức năng thường dài hơn một trang, khiến chúng ta khó có được khoảng cách rất xa giữa nơi mọi thứ được tuyên bố và nơi chúng được sử dụng. Bạn đang hoạt động trong phạm vi 0-20 và ngụy biện rằng có thể 7 là ổn trong trường hợp cụ thể này, trong khi anh chàng đưa ra quy tắc sẽ YÊU THÍCH để có 7 dòng và cố gắng nói chuyện với ai đó từ 700. Và tiếp tục trên hết, trong Visual Studio, bạn có thể di chuột qua bất cứ thứ gì và xem loại của nó, nó có phải là biến thành viên không, v.v. Điều đó có nghĩa là cần phải xem dòng khai báo nó được giảm bớt.

Đây vẫn là một quy tắc khá hợp lý, một quy tắc thực sự khá khó để phá vỡ những ngày này, và một quy tắc mà không ai từng ủng hộ là lý do để viết mã chậm. Hãy nhạy cảm, trên hết.


Cảm ơn câu trả lời của bạn. Nhưng chắc chắn bất kể kiểu dữ liệu, một thể hiện mới được tạo ra trên mỗi lần lặp theo cách tôi làm? Chỉ là trong trường hợp thứ hai, chúng ta không yêu cầu tham chiếu bộ nhớ mới mỗi lần. Hoặc tôi đã bỏ lỡ điểm? Và bạn có nói rằng trình tối ưu hóa C # sẽ tự động cải thiện mã của tôi khi nó biên dịch không? Tôi không biết điều đó!
James

2
Chi phí tạo int là rất nhỏ. Nếu bạn đang xây dựng một cái gì đó phức tạp, chi phí sẽ là một vấn đề lớn hơn.
Kate Gregory

17
Đó không chỉ là một câu hỏi về việc có thể nhìn thấy loại của nó và như vậy. Đó cũng là một câu hỏi của cuộc sống. Nếu biến "wibble" được khai báo 30 dòng trước khi nó được sử dụng lần đầu tiên, thì có 30 dòng trong đó việc sử dụng nhầm "wibble" có thể dẫn đến lỗi. Nếu nó được khai báo ngay trước khi sử dụng, sử dụng "wibble" trong 30 dòng trước đó sẽ không gây ra lỗi. Nó sẽ gây ra lỗi trình biên dịch thay thế.
Mike Sherrill 'Nhớ lại mèo'

Trong trường hợp này, một thể hiện mới không được tạo ra mỗi vòng lặp. Một biến cấp cao nhất được tạo và sử dụng cho mỗi lần lặp (nhìn vào IL). Nhưng đó là một chi tiết thực hiện.
thecoop

"Trong Visual Studio, bạn có thể di chuột qua bất cứ thứ gì và xem" vv Ngoài ra còn có Điều hướng để định nghĩa, trong đó có phím tắt F12không thể thiếu.
StuperUser

15

Việc xác định biến bên trong vòng lặp chỉ hiển thị cục bộ cho vòng lặp đó. Điều này có ít nhất 3 lợi thế cho người đọc:

  1. Định nghĩa biến và bất kỳ ý kiến ​​liên quan đều dễ dàng tìm thấy
  2. Người đọc biết rằng biến này không bao giờ được sử dụng ở nơi khác (không phụ thuộc vào mong đợi)
  3. Khi mã được viết hoặc chỉnh sửa, không có khả năng bạn có thể sử dụng cùng một tên biến ngoài vòng lặp để tham chiếu đến biến đó nếu không, bạn có thể gặp lỗi.

Đối với bit hiệu quả, trình biên dịch là thông minh để tạo định nghĩa bên ngoài vòng lặp trong mã được tối ưu hóa được tạo. Biến sẽ không được tạo mỗi lần lặp.


4

Mọi người nói càng gần với cách sử dụng của họ càng tốt , Họ không nói rằng bạn nên làm điều đó mọi lúc, bởi vì một số trường hợp khai báo các biến trong phạm vi tối thiểu sẽ gây ra một số chi phí. Lý do chính của tuyên bố đó là Khả năng đọc và đưa ra các biến phạm vi nhỏ nhất bạn có thể.


4

Mặc dù nó giúp dễ đọc, nhưng khả năng đọc không phải là vấn đề chính trong trường hợp này và các IDE hiện đại không làm giảm nhu cầu của quy tắc này.

Mối quan tâm chính là các biến chưa được khởi tạo. Nếu bạn khai báo một biến quá xa so với khởi tạo của nó, nó sẽ mở ra cho bạn tất cả các loại vấn đề tiềm ẩn. Bạn có thể thấy mình vô tình làm việc với bất kỳ thứ gì có trong RAM trước đó, hoặc kết quả từ một phép tính cao hơn trong hàm hoặc khởi tạo giả (như 0) mà ai đó đưa vào chỉ để khiến trình biên dịch không phàn nàn. Mọi người sẽ chèn mã vào giữa khai báo và sử dụng của bạn mà không nhận thức được các điều kiện tiên quyết ngầm định của bạn cho biến đó. Trong trường hợp xấu nhất, việc sử dụng đó sẽ chỉ xảy ra để làm việc trong các thử nghiệm của bạn nhưng không thành công trong lĩnh vực này.

Khai báo các biến của bạn trong phạm vi càng nhỏ càng tốt và khởi tạo chúng thành một giá trị phù hợp ngay tại điểm khai báo sẽ tránh được rất nhiều vấn đề đau đầu về bảo trì. Thực tế là nó bắt buộc cải thiện khả năng đọc chỉ là một tác dụng phụ tốt đẹp.


1

Nó không phải là "phải". Đó chỉ là một ý kiến, tôi cách để làm một cái gì đó. Ví dụ, tôi muốn khai báo tất cả các vars trong các dòng đầu tiên của phương thức để tôi có thể nhận xét những gì tôi sẽ làm với các vars đó (tất nhiên trừ khi chúng là các quầy). Những người khác, như bạn đã nghe, muốn đặt họ càng gần với cách sử dụng của họ càng tốt (như trong ví dụ thứ hai bạn đã viết). Dù sao, ví dụ đầu tiên bạn cung cấp chắc chắn là một "lỗi" (theo nghĩa là nó sẽ gây ra chi phí như bạn hiểu).

Bạn chỉ cần chọn theo cách của bạn và làm theo nó.


2
Đó không chỉ là một ý kiến, phải không? Không phải nghiên cứu kỹ thuật phần mềm đã ghi lại mối quan hệ giữa thời gian sống và số lượng lỗi kể từ ít nhất là những năm 1980?
Mike Sherrill 'Nhớ lại mèo'

1

Hai ví dụ của bạn là mã khác nhau về chức năng, chúng không thể thay thế cho nhau. (Các ví dụ bị loại bỏ của bạn để lại cho nó một sự khác biệt mà không có sự khác biệt, nhưng trong mã không tầm thường, nó sẽ tạo ra sự khác biệt). Quy tắc trang web của bạn luôn phụ thuộc vào các cân nhắc phạm vi, như được chỉ ra bởi "... càng tốt".

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.