Чи повинні ми усунути локальні змінні, якщо можемо?


95

Наприклад, щоб підтримувати процесор в Android, я можу використовувати такий код:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

але я думаю , що локальні змінні powerManagerі wakeLockможе бути усунутий:

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

подібна сцена з’являється в режимі попередження iOS, наприклад: від

UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil];
[alert show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

до:

[[[UIAlertView alloc]
    initWithTitle:@"my title"
    message:@"my message"
    delegate:nil
    cancelButtonTitle:@"ok"
    otherButtonTitles:nil] show];

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [alertView release];
}

Чи є гарною практикою усунення локальної змінної, якщо вона просто використовується один раз в області застосування?


95
Не обов'язково. Іноді це робить код зрозумілішим для використання одноразових змінних, а в більшості гідних мов програмування для цих додаткових змінних дуже мало (якщо такі є) часу виконання.
Роберт Харві

75
Це також ускладнює перехід коду без налагоджувача. І ви також повинні бути впевнені (залежно від мови), що перший вираз не є NULL або помилкою.
GrandmasterB

78
Ні, це не так. Насправді, добре вводити локальні змінні для розбиття ланцюгів викликів методів. Створений машинний код, ймовірно, буде ідентичним, а вихідний код майже гарантовано є більш читабельним, отже, і кращим.
Кіліан Фот

48
Спробуйте це. Тепер підключіть налагоджувач і спробуйте побачити стан PowerManager або WakeLock. Усвідомте свою помилку. Раніше я думав те саме ("що з усіма цими місцевими жителями?"), Поки мені не довелося витрачати більшу частину часу на дослідження коду.
Фаеріндель

42
Навіть у вашому прикладі, у вашій «усуненій» версії є смуга прокрутки і вона не вміщується повністю на моєму екрані, що робить її набагато важче читати.
Ерік

Відповіді:


235

Код читається набагато частіше, ніж це написано, тому вам слід злітатись над бідною душею, якій доведеться читати код через півроку (це може бути ви) і прагнути до найяснішого, найпростішого для розуміння коду. На мою думку, перша форма з локальними змінними набагато зрозуміліша. Я бачу три дії на трьох рядках, а не три дії на одній лінії.

І якщо ви думаєте, що оптимізуєте що-небудь, позбувшись локальних змінних, ви не є. Сучасний компілятор введе powerManagerв регістр 1 , використовується локальна змінна чи ні, для виклику newWakeLockметоду. Те саме стосується і для wakeLock. Таким чином, ви отримуєте один і той же складений код в будь-якому випадку.

1 Якщо у вас було багато інтервенційного коду між декларацією та використанням локальної змінної, це може перейти на стек, але це незначна деталь.


2
Ви не можете знати, чи багато коду, оптимізатор може вбудувати деякі функції ... Інакше, домовлене, спочатку прагнення до читабельності - це правильний крок.
Матьє М.

2
Ну, я думаю, навпаки, якщо я бачу, як локальні змінні отримують ініціалізацію кратних разів на кожній функції, де вона використовується замість того, щоб бути атрибутами, коли вона може бути, я буду шукати, чому, в основному, я ретельно прочитаю рядки і порівняю їх просто з переконайтесь, що вони однакові. Тож я витрачу час.
Вальфрат

15
@Walfrat Локальні змінні, які ініціалізуються кілька разів? Ой. Ніхто не запропонував повторно використовувати місцевих жителів :)
Luaan

32
Учасники @Walfrat породжують побічні ефекти і їх слід використовувати лише тоді, коли ви спеціально хочете підтримувати стан між дзвінками до публічних членів. Це питання стосується використання локального для тимчасового зберігання проміжних обчислень.
Гусдор

4
Питання: Якщо ми можемо усунути локальні змінні? A: Ні.
simon

94

Деякі високооцінені зауваження заявили про це, але жодної відповіді, яку я бачив, не зробив, тому я додам це як відповідь. Ваш головний фактор у вирішенні цього питання:

Налагоджуваність

Часто розробники витрачають набагато більше часу та зусиль на налагодження, ніж написання коду.

За допомогою локальних змінних ви можете:

  • Точка зламу на лінії, куди вона призначена (з усіма іншими прикрасами точки точки розриву, такими як умовна точка розриву тощо)

  • Перевірте / дивіться / друкуйте / змінюйте значення локальної змінної

  • Ловіть проблеми, які виникають через касти.

  • Мають розбірливі сліди стека (лінія XYZ має одну операцію замість 10)

Без локальних змінних всі вищезазначені завдання або набагато складніші, надзвичайно важкі, або прямо неможливі, залежно від налагоджувача.

Таким чином, дотримуйтесь сумнозвісної максими (пишіть код так, як ніби наступний розробник, який підтримує його після себе, - божевільний лунатик, який знає, де ви живете), і помиляйтесь на стороні легшої налагодження , тобто використовуйте локальні змінні .


20
Я додам, що стек-траси набагато менш корисні, коли на одній лінії є багато дзвінків. Якщо у вас є виняток з нульовим вказівником на лінії 50, і на цьому рядку є 10 дзвінків, це не сильно звужує плаття. У виробничій заявці це часто є основна частина інформації, яку ви отримуєте зі звіту про дефекти.
JimmyJames

3
Переглянути код також набагато складніше. Якщо є call () -> call () -> call () -> call (), важко працювати за виклик третього методу. Набагато простіше, якщо є чотири локальні змінні
gnasher729

3
@FrankPuffer - ми маємо мати справу з реальним світом. Де налагоджувачі не роблять того, що ви пропонуєте.
DVK

2
@DVK: Насправді є більше налагоджувачів, ніж я думав, що дозволяють вам перевірити чи спостерігати будь-який вираз. MS Visual Studio (з версії 2013 року) має цю функцію для C ++ та C #. Eclipse має його для Java. В іншому коментарі Фаеріндель згадав IE11 для JS.
Френк Пуффер

4
@DVK: Так, багато реальних налагодників не роблять того, що я пропоную. Але це не має нічого спільного з першою частиною мого коментаря. Мені просто божевільно вважати, що людина, яка збирається підтримувати мій код, в основному буде взаємодіяти з ним за допомогою налагоджувача. Налагоджувачі відмінно підходять для певних цілей, але якщо вони отримують основний інструмент для аналізу коду, я б сказав, що щось серйозно не так, і я б спробував виправити це замість того, щоб зробити код більш налагоджуваним.
Френк Пуффер

47

Тільки якщо це полегшує розуміння коду. У ваших прикладах, я думаю, це ускладнює читання.

Усунення змінних у складеному коді є тривіальною операцією для будь-якого респектабельного компілятора. Ви можете перевірити висновок самостійно, щоб перевірити.


1
Це має стільки ж стосується стилю, скільки використання змінних. Питання відредаговано.
Джодрелл

29

Ваше запитання "чи вдала практика усунути локальну змінну, якщо вона просто використовується один раз у межах"? тестує неправильні критерії. Корисність локальної змінної не залежить від кількості її використання, але від того, чи робить код зрозумілішим. Позначення проміжних значень значущими іменами може підвищити чіткість у таких ситуаціях, як ця, яку ви представляєте, оскільки вона розбиває код на менші, більш легко засвоювані шматки.

На мій погляд, представлений вами немодифікований код зрозуміліший за ваш модифікований код, і тому його слід залишити без змін. Насправді, я б подумав витягнути локальну змінну зі зміненого коду, щоб поліпшити чіткість.

Я не очікував би впливу на продуктивність від локальних змінних, і навіть якщо він є, він, ймовірно, буде занадто малим, щоб його варто було б розглянути, якщо код не знаходиться в дуже тісному циклі в критичній швидкості частини програми.


Я думаю, що це має багато спільного зі стилізацією та використанням пробілів як нічого. Питання відредаговано.
Джодрелл

15

Може бути.

Особисто я б вагався з усуненням локальних змінних, якщо задіяний typecast. Я вважаю вашу компактну версію менш читаною, оскільки кількість дужок починає наближатися до ментальної межі. Він навіть вводить новий набір дужок, який не був потрібен у трохи більш детальній версії з використанням локальної змінної.

Виділення синтаксису, надане редактором коду, може певною мірою пом’якшити подібні проблеми.

На мій погляд, це кращий компроміс:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc").acquire();

Таким чином зберігаючи одну локальну змінну і вириваючи іншу. У C # я б використовував ключове слово var у першому рядку, оскільки typecast вже надає інформацію про тип.


13

Хоча я приймаю справедливість відповідей на користь місцевих змінних, я збираюся зіграти захисника диявола і викласти протилежний погляд.

Я особисто дещо проти використання локальних змінних виключно для того, що означає цілі документації, хоча сама причина вказує на те, що практика має значення: локальні змінні ефективно псевдодокументують код.

У вашому випадку головна проблема - відступ, а не відсутність змінних. Ви можете (і повинні) відформатувати код наступним чином:

((PowerManager)getSystemService(POWER_SERVICE))
        .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag")
        .acquire();

Порівняйте це з версією з локальними змінними:

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

За допомогою локальних змінних: імена додають деяку інформацію до читача, а типи чітко вказані, але фактичні виклики методу менш помітні і (на мою думку) він не читається так чітко.

Без використання локальних змінних: це більш стисло і виклики методів видніші, але ви можете запитати більше інформації про те, що повертається. Однак деякі ІДЕ можуть вам це показати.

Ще три коментарі:

  1. На мою думку, додавання коду, який не має функціонального використання, іноді може викликати збиття з пантелику, оскільки читач повинен усвідомити, що він справді не має функціонального використання і просто існує для «документації». Наприклад, якщо цей метод був довжиною 100 рядків, не було б очевидно, що локальні змінні (і, отже, результат виклику методу) не потрібні були в якийсь пізній момент, якщо ви не прочитали весь метод.

  2. Додавання локальних змінних означає, що ви повинні вказати їх типи, і це вводить залежність у коді, яка інакше не була б там. Якщо тип повернення методів тривіально змінився (наприклад, він був перейменований), вам доведеться оновити свій код, тоді як без локальних змінних ви не стали б.

  3. Налагодження може бути простішим з локальними змінними, якщо ваш налагоджувач не показує значення, повернені з методів. Але виправленням цього є виправлення недоліків у налагоджувачах, а не зміна коду.


Щодо ваших подальших коментарів: 1. Це не повинно бути проблемою, якщо ви дотримуєтесь конвенції про те, що локальні змінні оголошуються якомога ближче до того, де вони використовуються, і ви тримаєте свої методи розумною тривалістю. 2. Не в мові програмування з умовиводом типу. 3. Добре написаний код часто взагалі не потребує налагодження.
Роберт Харві

2
Ваш перший приклад коду працює лише у тому випадку, якщо ви створюєте свої об'єкти за допомогою вільних інтерфейсів або "будівельника", які я б не використовував скрізь у своєму коді, а лише вибірково.
Роберт Харві

1
Я думаю, що питання передбачає, що локальні змінні функціонально надлишкові, а тому такий тип інтерфейсу необхідний для випадку. Ми, мабуть, могли б домогтися видалення місцевих жителів, якби це було інакше через різні викривлення, але я мав на увазі, що ми розглядали простий випадок.
rghome

1
Я вважаю ваш варіант ще гіршим для читабельності. Можливо, я занадто сильно піддався впливу VB.net, але першим моїм побаченням зразка є "Куди пішов оператор WITH? Я випадково видалив його?" Мені потрібно двічі подивитися, що відбувається, і це не добре, коли мені потрібно переглянути код через багато місяців.
Тонні

1
@Тонні для мене, це читабельніше: місцеві жителі не додають нічого не очевидного з контексту. У мене на голові Java, тому ніяких withзаяв немає . Було б нормальним умовою форматування форматів на Java.
rghome

6

Тут напруженість мотивацій. Введення тимчасових змінних може полегшити читання коду. Але вони також можуть запобігти та ускладнити бачення інших можливих рефактори, таких як метод вилучення та замінити темп на запит . Ці останні типи рефактори, коли це доречно, часто дають набагато більші переваги, ніж тимчасова змінна.

Про мотивацію цих останніх рефакторинга Фоулер пише :

"Проблема темпів полягає в тому, що вони тимчасові та локальні. Оскільки їх можна бачити лише в контексті методу, в якому вони використовуються, темпи, як правило, заохочують більш тривалі методи, тому що це єдиний спосіб досягти температури. замінивши temp методом запиту, будь-який метод у класі може отримати інформацію. Це дуже допомагає придумати чистіший код для класу. "

Так, так, використовуйте temps, якщо вони роблять код більш читабельним, особливо якщо це локальна норма для вас та вашої команди. Але будьте в курсі, що це може іноді ускладнювати помітні більші альтернативні вдосконалення. Якщо ви зможете розвинути свою здатність відчувати, коли варто їхати без таких темпів, і стати більш комфортним при цьому, то, мабуть, це добре.

FWIW Я особисто уникав читати книгу Фаулера "Рефакторинг" протягом десяти років, бо уявляв, що не можна багато сказати на такі відносно прості теми. Я абсолютно помилявся. Коли я зрештою прочитав це, це змінило мою щоденну практику кодування, набагато на краще.


1
Чудова відповідь. Найкращий код, який я писав (і я бачив від інших), часто мав безліч малих (2, 3 рядки) методів, які могли б замість таких змінних temp. З цим пов'язано суперечливе сприйняття приватних методів ... Добре продуманий, і я часто вважаю це правдою.
Штійн де Вітт

Темпи цього питання вже стосуються функцій, тому ця відповідь не має значення для питання ОП.
user949300

@ user949300 Я не думаю, що це не має значення. Так, темпи в конкретному прикладі ОП - це повернені значення функцій або методів. Але в ОП дуже зрозуміло, що це лише приклад сценарію. Актуальне питання є набагато більш загальним: "чи слід усунути тимчасові змінні, коли зможемо"
Джонатан Хартлі

1
Гаразд, я проданий, ** намагався ** змінити свій голос. Але часто, коли я виходжу за рамки обмеженого кола питання про ОП, мені стає нудно. Так може бути непостійним ... :-). Е, не можу змінити мій голос, поки ви не редагуєте, що завгодно ...
user949300

@ user949300 Свята корова! Людина, яка передумує при продуманому розгляді питань! Ви, пане, рідкість, і я надіваю вам шапку.
Джонатан Хартлі

3

Ну, це гарна ідея усунути локальні змінні, якщо ви зможете зробити код тим більше читабельним. Цей довгий твій лайнер не читабельний, але тоді він слідує досить багатослівному стилю ОО. Якби ви могли звести це до чогось подібного

acquireWakeLock(POWER_SERVICE, PARTIAL, "abc");

тоді я б сказав, що це, мабуть, буде гарною ідеєю. Можливо, ви можете ввести допоміжні методи, щоб звести їх до чогось подібного; якщо такий код з’являється декілька разів, то він цілком може бути корисним.


2

Розглянемо тут Закон Деметера . У статті Вікіпедії про LoD зазначено наступне:

Закон Деметера для функцій вимагає, щоб метод m об’єкта O міг викликати лише методи таких типів об'єктів: [2]

  1. O себе
  2. m параметри
  3. Будь-які об'єкти, створені / створені в межах m
  4. О прямі компоненти об'єктів
  5. Глобальна змінна, доступна O, в області m

Одним із наслідків виконання цього Закону є те, що вам слід уникати використання методів об'єктів, повернених іншими методами, у довгій рядку з пунктиром, як показано у другому прикладі вище:

((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag").acquire();

Дійсно важко зрозуміти, що це робить. Щоб зрозуміти це, ви повинні зрозуміти, що робить кожна процедура, а потім розшифрувати, яка функція викликається на якому об'єкті. Перший блок коду

PowerManager powerManager=(PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock=powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"abc");
wakeLock.acquire();

чітко показує, що ви намагаєтеся зробити - ви отримуєте об’єкт PowerManager, отримуєте об'єкт WakeLock від PowerManager, а потім отримуєте wakeLock. Вище викладено правило №3 LoD - ви створюєте інстанцію цих об'єктів у своєму коді, і, таким чином, можете використовувати їх для того, щоб зробити все, що вам потрібно.

Можливо, інший спосіб задуматися над тим, щоб пам’ятати, що при створенні програмного забезпечення слід писати для ясності, а не для стислості. 90% всієї розробки програмного забезпечення - це обслуговування. Ніколи не пишіть шматочок коду, який ви не раді б підтримувати.

Удачі.


3
Мені було б цікаво, як синтаксис рідини вписується в цю відповідь. При правильному форматуванні синтаксис флюїду легко читається.
Гусдор

12
Це не те, що означає "Закон Деметера". Закон Деметра - це не підрахунок точок; це по суті означає "говорити тільки з вашими найближчими друзями".
Роберт Харві

5
Доступ до тих же методів та членів через проміжну змінну все ще є настільки ж серйозним порушенням закону Деметра. Ви просто затьмарили його, а не виправили.
Джонатан Хартлі

2
З точки зору "Закону про Деметра", обидві версії однаково "погані".
Халк

@Gusdor погодився, це більше коментар до стилю у прикладі запитання. Питання відредаговано.
Джодрелл

2

Варто зазначити, що код читається часто, на різну "глибину". Цей код:

PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();

легко «скувати». Це 3 твердження. Спочатку ми придумали PowerManager. Тоді ми придумуємо a WakeLock. Тоді ми . Я це легко бачу, просто переглядаючи початок кожного рядка; прості призначення змінних дійсно легко розпізнати частково як "Тип varName = ..." і просто подумки переглядати "...". Аналогічно, останнє твердження, очевидно, не є формою завдання, але воно містить лише два імені, тому "головна суть" відразу видно. Часто це все, що мені потрібно було б знати, якби я просто намагався відповісти "що робить цей код?" на високому рівні.acquirewakeLock

Якщо я переслідую тонку помилку, яку, на мою думку, є тут, то, очевидно, мені потрібно буде детальніше розібратися над цим, і я фактично запам'ятаю "..." с. Але окрема структура тверджень все ще допомагає мені робити це одне твердження за часом (особливо корисно, якщо мені потрібно заглибитись у реалізацію речей, що викликаються у кожному операторі; коли я повертаюся назад, я повністю зрозумів "одну одиницю" а потім можна перейти до наступного твердження).

((PowerManager)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
    .acquire();

Зараз це все одне твердження. Структуру верхнього рівня не так просто прочитати; в оригінальній версії ОП, без перерв рядків і відступів для візуальної передачі будь-якої структури, мені довелося б порахувати дужки, щоб розшифрувати її на послідовність з 3 кроків. Якщо деякі виразки з декількох частин вкладаються один у одного, а не розташовуються як ланцюжок викликів методів, то це все одно може виглядати схожим на це, тому я повинен бути обережним, довіряючи цьому, не рахуючи дужок. І якщо я довіряю відступі і просто просуваюся вперед до останнього, як передбачуваного пункту всього цього, що .acquire()мені скаже самостійно?

Хоча іноді це може бути те, що ти хочеш. Якщо я застосую ваше перетворення наполовину і написав:

WakeLock wakeLock =
     ((PowerManeger)getSystemService(POWER_SERVICE))
    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();

Тепер це доводиться до швидкої роботи: "дістань WakeLock, тоді acquireце". Навіть простіша, ніж перша версія. Одразу очевидно, що річ, яку набувають, - це WakeLock. Якщо отримання - PowerManagerце лише детальна деталь, яка є несуттєвою для цього коду, але wakeLockце важливо, тоді це може допомогти поховати PowerManagerречі, тому природно скуповувати над ним, якщо ви просто намагаєтесь швидко отримати ідея того, що робить цей код. І не називаючи це означає, що він використовується лише один раз, а іноді і так що важливо (якщо решта області дуже довга, мені доведеться прочитати все це, щоб сказати, чи вона коли-небудь використовується знову; хоча використання явних підсферів може бути іншим способом вирішити це, якщо ваша мова їх підтримує).

Що означає, що все залежить від контексту та того, що ви хочете спілкуватися. Як і при написанні прози природною мовою, завжди існує багато способів написати заданий фрагмент коду, який в основному є еквівалентним за змістом інформації. Як і при написанні прози природною мовою, як вибираєте між ними, як правило, не слід застосовувати механістичні правила типу "усунення будь-якої локальної змінної, яка виникає лише один раз". Швидше якви вирішите записати свій код, буде підкреслювати деякі речі, а де-акцентувати - інші. Ви повинні прагнути робити ці рішення свідомо (включаючи вибір, щоб часом писати менш читабельний код з технічних причин), виходячи з того, що ви насправді хочете підкреслити. Особливо подумайте про те, що послужить читачам, яким просто потрібно «отримати суть» вашого коду (на різних рівнях), оскільки це станеться набагато частіше, ніж дуже близьке читання за виразом «за виразом».


Для мене, навіть якщо я не знаю API, це дуже очевидно, що робить код, навіть без змінних. getSystemService(POWER_SERVICE)отримує менеджер живлення. .newWakeLockотримує фіксатор. .acquireнабуває його. Гаразд, я не знаю всіх типів, але я можу це знайти в IDE, якщо потрібно.
rghome

Вам може бути очевидно, що повинен робити код , але ви не маєте поняття, що він насправді робить. Якщо я шукаю помилку, все, що я знаю, - це те, що якийсь код десь не робить того, що він повинен робити, і я повинен знайти, який код.
gnasher729

@ gnasher729 Так. Полювання на помилок було прикладом, який я наводив, коли вам потрібно було б уважно прочитати всі подробиці. І одна з речей, яка насправді допомагає знайти код, який не робить те, що він повинен робити, - це мати можливість легко зрозуміти, яким був задум оригіналу автора.
Бен

коли я повертаюся назад, я повністю зрозумів "одну одиницю" і потім переходжу до наступного твердження. Насправді ні. Насправді локальні змінні перешкоджають цьому повного розуміння. Тому що вони все ще затримуються ... займаючи ментальний простір ... що з ними станеться в наступних 20 заявах ... барабанне прокручування ... Без місцевих жителів ви були б впевнені, що об'єкти пішли і неможливо нічого зробити з ними в наступних рядках. Не потрібно пам’ятати про них. Мені подобається returnякнайшвидше від методів, наскільки це можливо, з тієї ж причини.
Штійн де Віт

2

Це навіть антипатерн із власною назвою: Train Wreck . Уже зазначено кілька причин уникнення заміни:

  • Важче читати
  • Складніше налагоджувати (як для перегляду змінних, так і для виявлення локацій винятків)
  • Порушення закону про деметер (LoD)

Поміркуйте, чи цей метод занадто багато знає з інших об'єктів. Методи ланцюга - це альтернатива, яка може допомогти вам зменшити зв'язок.

Також пам’ятайте, що посилання на об’єкти дійсно дешеві.


Ем, чи не переглянуті способи ланцюга методів? EDIT прочитайте пов’язану статтю, тому я зараз бачу різницю Дуже гарна стаття дякую!
Штійн де Віт

Дякуємо за перегляд. У будь-якому випадку, ланцюжок методів може працювати в деяких випадках, тоді як просто вихід змінної може бути відповідним рішенням. Завжди добре знати, чому люди не згодні з вашою відповіддю.
Борджаб

Я здогадуюсь, що навпаки "Аварія поїздів" - "Місцева лінія". Це поїзд між двома великими містами, який зупиняється в кожному селі країни лише на випадок, якщо хтось захоче ввійти або вийти, хоча більшість днів ніхто не робить.
rghome

1

Поставлене запитання: "Чи слід усунути локальні змінні, якщо зможемо"?

Ні, ви не повинні ліквідувати лише тому, що можете.

Дотримуйтесь інструкцій з кодування у вашому магазині.

Здебільшого локальні змінні полегшують код для читання та налагодження.

Мені подобається те, що ти робив PowerManager powerManager. Для мене нижній регістр класу означає, що це просто разове використання.

Коли цього не слід, якщо змінна збирається затримувати дорогі ресурси. У багатьох мовах є синтаксис локальної змінної, який потрібно очистити / випустити. У C # він використовується.

using(SQLconnection conn = new SQLconnnection())
{
    using(SQLcommand cmd = SQLconnnection.CreateCommand())
    {
    }
}

Це насправді не пов’язано з локальними змінними, але з очищенням ресурсів ... Я не добре розбираюся в C #, але я був би здивований, якби using(new SQLConnection()) { /* ... */ }не було також законним (чи корисно це буде іншим питанням :).
Штійн де Віт

1

Один важливий аспект не згадується в інших відповідях: Щоразу, коли ви додаєте змінну, ви вводите змінений стан. Зазвичай це погано, тому що робить ваш код складнішим і, таким чином, важче зрозуміти та перевірити. Звичайно, чим менший обсяг змінної, тим менше питання.

Те, що ви хочете, насправді не змінна, значення якої можна змінити, а тимчасова константа. Тому подумайте виразити це у своєму коді, якщо ваша мова це дозволяє. На Java ви можете використовувати, finalа в C ++ ви можете використовувати const. У більшості функціональних мов це поведінка за замовчуванням.

Це правда, що локальні змінні є найменш шкідливим типом стану, що змінюється. Змінні учасника можуть спричинити набагато більше проблем, а статичні змінні - ще гірші. І все-таки я вважаю важливим викласти якомога точніше у своєму коді те, що він повинен робити. І існує велика різниця між змінною, яку можна було б змінити пізніше, і простою назвою для проміжного результату. Тож якщо ваша мова дозволяє висловити цю різницю, просто зробіть це.


2
Я не спростував вашої відповіді, але я б припустив, що це пов'язано з тим, що локальні змінні в загальних мовах загалом не вважаються "державними", якщо ви не говорите про якийсь тривалий метод. Я погоджуюся на використання final / const як найкращої практики, але навряд чи введення змінної для простого розбиття ланцюгового дзвінка призведе до проблем, викликаних станом, що змінюється. Насправді використання локальних змінних допомагає впоратися зі станом, що змінюється. Якщо метод може повертати різні значення в різний час, в іншому випадку ви можете виявити деякі справді цікаві помилки.
JimmyJames

@JimmyJames: До моєї відповіді додали пояснення. Але є одна частина вашого коментаря, яку я не зрозумів: "використання локальних змінних допомагає впоратися зі станом, що змінюється". Чи можете ви пояснити це?
Френк Пуффер

1
Наприклад, скажімо, що мені потрібно перевірити значення, і якщо воно перевищує 10, натисніть сповіщення. Припустимо, це значення походить від методу getFoo(). Якщо я уникаю локальної декларації, я if(getFoo() > 10) alert(getFoo());закінчу, але ButFFo () може повернути різні значення для двох різних викликів. Я міг би надіслати попередження зі значенням, меншим або рівним 10, яке в кращому випадку заплутало і повернеться до мене як дефект. Така річ стає важливішою з одночасністю. Місцеве призначення - атомне.
JimmyJames

Дуже хороший момент. Може бути причина , чому я не люблю ці місцеві жителі .... Ви збираєтеся зробити що - то з цим , наприклад , після виклику цього методу? Дозвольте перевірити решту методу .... ммм ок ні. І ця річ, яку ви отримали ... що ви робите з цим (сканування решти методу ще раз) ... ммм знову нічого ... гаразд, чому вони там? О так, це повинно бути читабельніше ... але без них я впевнений, що ти їх більше не використовуєш, тому мені не доведеться читати решту методу. PowerManagerWakeLock
Штійн де Віт

У недавній розмові доповідач стверджував, що найкращий спосіб показати, що змінна є остаточною, - це писати короткі методи, коли очевидно, що змінна не змінюється . Якщо finalпотрібна локальна змінна методу, ваш метод занадто довгий.
user949300
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.