Ваш вопрос в контексте сокращения стандартного кода путем создания пользовательского компонента с высокой возможностью повторного использования и обслуживания.
blockquote>Таким образом, вы можете достичь этого с помощью 4 простых шагов:
1. Создайте каталог приложения как:
-\resources (parent resource directory) -\menus (store all menus list constants) -\values -\app_strings.dart (store all strings constants) -\app_colors.dart (store all colors constants) -\app_styles.dart (store all styles i.e. material dark, light, cupertino etc.) -\app_dimens.dart (store all dimension constants) -\components (parent component directory) -\your_custom_widget.dart(create custom component here) -\..... -\views -\your_view.dart(your view where you import custom component)
2. Создание констант ресурса:
Это очень простые шаги, так как вы должны добавлять только константы в соответствующие файлы ресурсов.
Пример - создание цветовых констант в
app_colors.dart
import 'package:flutter/material.dart'; /// App Colors Class - Resource class for storing app level color constants class AppColors { static const Color PRIMARY_COLOR = Color(0xFF35B4C5); static const Color PRIMARY_COLOR_LIGHT = Color(0xFFA5CFF1); static const Color PRIMARY_COLOR_DARK = Color(0xFF0D3656); static const Color ACCENT_COLOR = Color(0xFFF2DA04); }
3. Создайте пользовательские компоненты:
Теперь в каталоге
components
создайте пользовательский виджет как:class CustomWidget extends StatefulWidget{ // Declare your widget parameters final data-type your_parameter; ..... ..... ..... // Create constant constructor const CustomWidget( // Initialize all your widget parameters this.your_parameter ..... ..... .....) @override _CustomWidgetState createState() => _CustomWidgetState(); } /// CustomWidget State class class _CustomWidgetState extends State<CustomWidget>{ // Here you should use existing widget from either material library or cupertino etc @override Widget build(BuildContext context) { return ExistingBaseWidget( // Set here all necessary parameters for customization // For setting constansts from resources you do it like this color : AppColors.COLOR_NAME, radius : AppDimens.BORDER_RADIUS, ....... ); } }
4. Импортируйте пользовательский виджет в любые виды: В любые виды вы можете импортировать пользовательские виджеты, как использовать
child: CustomWidget( // Initialize all required parameters )
Преимущества
- [1120 ] В будущем, когда вы захотите изменить свои пользовательские виджеты или константы ресурсов, вам придется менять их только в одном месте, и они будут отражаться во всех местах.
Также вы можете использовать эти пользовательские виджеты и константы ресурсов во всех ваших проектах с незначительными изменениями.
Код представлений выглядит более понятным и понятным.
Короткий ответ: объявите переменную максимально близко к первому использованию и инициализируйте, чтобы "обнулить", если Вы все еще должны.
Длинный ответ: Если Вы объявляете переменную в начале функции и не используете ее до позже, необходимо пересмотреть размещение переменной к максимально локальному объему. Можно затем обычно присваивать ему необходимое значение сразу же.
Если необходимо объявить, что это деинициализировало, потому что это присвоено в условном выражении, или передало ссылкой и присвоилось к, инициализирование его к пустой эквивалентной стоимости является хорошей идеей. Компилятор может иногда сохранять Вас, если Вы компилируете под - Стена, поскольку это предупредит, если Вы будете читать из переменной прежде, чем инициализировать его. Однако этому не удается предупредить Вас при передаче его функции.
Если Вы избегаете рискованных действий и устанавливаете его на пустое эквивалентное, Вы не причинили вреда функция при передаче его перезаписям он. Однако, функция при передаче его использованию значение Вам можно в значительной степени гарантировать, приведя утверждение к сбою (если у Вас будет один), или по крайней мере segfaulting второе Вы используете несуществующий объект. Случайная инициализация может сделать все виды плохих вещей, включая "работу".
Просто вторичное наблюдение. Инициализации только ЛЕГКО оптимизированы на типах примитивов или при присвоении функциями константы.
a = нечто ();
a = foo2 ();
Не может быть легко оптимизирован, потому что нечто может иметь побочные эффекты.
Также выделения "кучи" перед временем могли бы привести к огромным хитам производительности. Возьмите код как
void foo(int x)
{
ClassA *экземпляр = новый ClassA ();
//... сделайте что-то не "экземпляр", связанный... если (x> 5) {
delete instance;
return;
}
//.. сделайте что-то, что использует экземпляр
}
На том случае просто объявите экземпляр как раз в то самое время, когда Вы будете использовать его, и инициализировать его только там. И не компилятор не Может оптимизировать это для Вас, так как у конструктора могут быть побочные эффекты, которые изменило бы переупорядочение кода.
править: Я перестал работать при использовании функции :P листинга кода
Я думаю, что это - в большинстве случаев плохая идея инициализировать переменные со значением по умолчанию, потому что это просто скрывает ошибки, которые легко найдены с неинициализированными переменными. Если Вы забываете получать и устанавливать фактическое значение или удалять получить код случайно, Вы, вероятно, никогда не замечаете его, потому что 0 во многих случаях рыночная стоимость. Главным образом намного легче инициировать те ошибки со значением>> 0.
Например:
void func(int n)
{
int i = 0;
... // Many lines of code
for (;i < n; i++)
do_something(i);
Через какое-то время Вы собираетесь добавить некоторый другой материал.
void func(int n)
{
int i = 0;
for (i = 0; i < 3; i++)
do_something_else(i);
... // Many lines of code
for (;i < n; i++)
do_something(i);
Теперь Ваш второй цикл не запустится с 0, но с 3, в зависимости от того, что делает функция может быть очень трудно найти, что существует даже ошибка.
Как простой пример, можно ли определить то, что это будет инициализировано к (C/C++)?
bool myVar;
У нас была проблема в продукте, который будет иногда рисовать изображение на экране и иногда не, обычно в зависимости от того, кто машина, с которой он был создан. Оказалось, что на моей машине это инициализировалось ко лжи, и на машине коллег это инициализировалось к истинному.
Иногда переменная используется для "собирания" результата более длинного блока вложенного ifs/elses... В тех случаях я иногда сохраняю переменную неинициализированной, потому что она должна быть инициализирована позже одним из условных переходов.
Прием: если я оставляю это неинициализированным сначала и затем существует ошибка в длинном, если/еще блок так переменная никогда не присваивается, я вижу, что ошибка в Valgrind :-) который, конечно, требует для частого выполнения кода (идеально регулярные тесты) через Valgrind.
Поскольку Вы имеете, показал относительно производительности, это не имеет значения. Компилятор будет (в оптимизированных сборках), обнаруживают, если локальная переменная записана, не будучи считанным из, и удалите код, если это не имеет другие побочные эффекты.
Это сказало: при инициализации материала с простыми операторами только, чтобы быть уверенными, что он инициализировал, хорошо делать так.. Я лично не делаю этого по единственной причине:
Это обманывает парней, которые могут позже поддержать Ваш код в размышление, что инициализация требуется. То небольшое нечто = 0; увеличит сложность кода. Кроме этого это - просто вопрос вкуса.
Если Вы, unnessesary инициализируют переменные через сложные операторы, это может иметь побочный эффект.
Например:
float x = sqrt(0);
Может быть оптимизирован Вашим компилятором, если Вы удачливы и работаете с умным компилятором. С не так умный компилятор это может также привести к дорогостоящему и unnessesary вызову функции, потому что sqrt может - поскольку побочный эффект - установил errno переменную.
Если Вы вызываете функции, которые Вы определили сами, мой лучший выбор, что компилятор всегда предполагает, что они могут иметь побочные эффекты и не оптимизируют их. Это может отличаться, если функция, оказывается, находится в той же единице перевода, или Вам включили целую оптимизацию программы.
Да: всегда инициализируйте свои переменные, если у Вас нет очень серьезного основания не к. Если мой код не потребует конкретного начального значения, то я буду часто инициализировать переменную к значению, которое гарантирует явную ошибку, если код, который следует, будет взломан.
Всегда инициализируйте локальные переменные для обнуления, по крайней мере. Как Вы видели, нет никакой реальной производительности этого.
int i = 0;
struct myStruct m = {0};
Вы в основном добавляете 1 или 2 инструкции по сборке, если это. На самом деле много времени выполнения C сделают это для Вас на сборке "Выпуска", и Вы не будете изменять вещь.
Но Вы должны initalize это, потому что у Вас теперь будет та гарантия.
Одна причина не инициализировать имеет отношение к отладке. Некоторое время выполнения, например, MS CRT, инициализирует память с предопределенными и зарегистрированными шаблонами, которые можно определить. Таким образом, когда Вы льетесь через память, Вы видите, что память является действительно неинициализированной, и это не использовалось и сбрасывалось. Это может быть полезно в отладке. Но это во время отладки.
В C/C++ я полностью соглашаюсь с Вами.
В Perl, когда я создаю переменную, она автоматически помещается в значение по умолчанию.
my ($val1, $val2, $val3, $val4);
print $val1, "\n";
print $val1 + 1, "\n";
print $val2 + 2, "\n";
print $val3 = $val3 . 'Hello, SO!', "\n";
print ++$val4 +4, "\n";
Они все установлены на undef первоначально. Undef является ложным значением и заполнителем. Из-за динамического контроля типов, если я добавляю число к нему, оно предполагает, что моя переменная является числом и заменяет undef eqivilent ложным значением 0. Если я делаю строковые операции, ложная версия строки является пустой строкой, и этим автоматически заменяют.
[jeremy@localhost Code]$ ./undef.pl
1
2
Hello, SO!
5
Таким образом для Perl, по крайней мере, объявляют рано и не волнуются. Тем более, что большинство программ имеет много переменных. Вы используете меньше строк, и это выглядит более чистым без явной инициализации.
my($x, $y, $z);
:-)
my $x = 0;
my $y = 0;
my $z = 0;
Иногда Вам нужна переменная как заполнитель (например, использование ftime
функции), таким образом, не имеет смысла инициализировать их прежде, чем вызвать функцию инициализации.
Однако это не было бы плохо, по-моему, для аннотирования того, что Вы знаете о ловушках, чем-то в способе
uninitialized time_t t;
time( &t );
Это принадлежит C++ только, но между этими двумя методами существует определенное различие. Давайте предположим, что у Вас есть класс MyStuff
, и Вы хотите инициализировать его другим классом. Вы могли сделать что-то как:
// Initialize MyStuff instance y
// ...
MyStuff x = y;
// ...
То, что это на самом деле делает, вызвать конструктора копии x. Это совпадает с:
MyStuff x(y);
Это отличается, чем этот код:
MyStuff x; // This calls the MyStuff default constructor.
x = y; // This calls the MyStuff assignment operator.
Конечно, совершенно другой код называют когда построение копии по сравнению с построением значения по умолчанию + присвоение. Кроме того, единственный вызов конструктору копии, вероятно, будет более эффективным, чем конструкция, сопровождаемая присвоением.
Позвольте мне рассказать Вам историю о продукте, я продолжил работать в 1992 и позже что в целях этой истории мы назовем Stackrobat. Мне присвоили ошибка, которая заставила приложение отказывать на Mac, но не в Windows, о, и ошибка не была восстанавливаема надежно. Это приняло QA лучшее участие недели для предложения рецепта, который работал, возможно, каждый 10-й раз.
Это был ад, разыскивающий первопричину, так как фактический катастрофический отказ произошел много позже действия, которое сделало это.
В конечном счете я разыскал его путем записи профилировщику пользовательского кода для компилятора. Компилятор вполне счастливо ввел бы вызовы к глобальному prof_begin () и prof_end () функции, и Вы были свободны реализовать их сами. Я записал профилировщику, который взял обратный адрес от стека, нашел инструкцию по созданию стекового фрейма, определил местоположение блока на стеке, который представил местных жителей для функции и покрыл их вкусным слоем дерьма, которое вызвало бы ошибку шины, если бы какой-либо элемент был разыменован.
Это поймало что-то как полдюжина ошибок указателей, используемых перед инициализацией, включая ошибку, которую я искал.
То, что произошло, было то, что большую часть времени стек, оказалось, имел значения, которые были по-видимому мягки, если они были разыменованы. Другие времена значения вызвали бы приложение к ружью его собственная "куча", вынув приложение когда-то намного позже.
Я провел больше чем две недели, пытаясь найти эту ошибку.
Урок: инициализируйте своих местных жителей. Если кто-то лает производительность на Вас, покажите им этот комментарий и скажите им, что Вы провели бы две недели, работая представляющий код и устраняющий узкие места вместо того, чтобы иметь необходимость разыскать ошибки как это. Средства отладки и средства проверки "кучи" получили путь лучше, так как я должен был сделать это, но вполне откровенно они поправились для компенсации ошибок от плохих методов как это.
Если Вы не работаете на крошечной системе (встроенный, и т.д.), инициализация местных жителей должна быть почти бесплатной. ПЕРЕМЕСТИТЕСЬ/ЗАГРУЗИТЕ инструкции очень, очень быстро. Напишите код, чтобы быть твердыми и удобными в сопровождении сначала. Осуществите рефакторинг его, чтобы быть производительной секундой.
Это - яркий пример Преждевременной оптимизации, корень всего зла
Полная кавычка:
Нет сомнения, что чаша Грааля эффективности ведет для злоупотребления. Программисты тратят впустую огромное количество времени, думающее об или вызывающее беспокойство о, скорость некритических частей их программ, и эти попытки эффективности на самом деле оказывают сильное негативное влияние, когда отладку и обслуживание рассматривают. Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла. Все же мы не должны отказываться от наших возможностей в этом критические 3%. Хороший программист не будет убаюкан в самодовольство таким обоснованием, он будет мудр для осторожного рассмотрения критического кода; но только после того, как тот код был определен.
Это прибыло от Donald Knuth., кто Вы собираетесь верить... своим коллегам или Knuth?
Я знаю, где мои деньги...
Возвращаться к исходному вопросу: "Мы должны ПЕРЕДАТЬ ПОД МАНДАТ инициализацию?"
Я формулировал бы его как так:
Переменные должны быть, инициализируют, кроме ситуации, где можно продемонстрировать, что существует значительное увеличение производительности, которое будет реализовано, не инициализируя. Приезжайте вооруженные твердыми числами...
Я не уверен, необходимо ли "сделать их обязательными", но я лично думаю, что всегда лучше инициализировать переменные. Если цель приложения состоит в том, чтобы быть максимально трудной затем, C/C++ открыт с этой целью. Однако я думаю, что многие из нас были записаны время или два, не инициализировав переменную и предположив, что она содержит допустимое значение (например, указатель), когда она действительно не делает. Указатель с адресом нуля намного легче проверить на то, чем если бы он имеет случайный мусор от последнего содержания памяти в том конкретном местоположении. Я думаю в большинстве случаев, это больше не вопрос производительности, а вопрос ясности и безопасности.
Это должно быть главным образом обязательно. Причина этого не имеет никакого отношения к производительности, а скорее опасности использовать unitialized переменную. Однако существуют случаи, где это просто выглядит смешным. Например, я видел:
struct stat s;
s.st_dev = -1;
s.st_ino = -1;
s.st_mode = S_IRWXU;
s.st_nlink = 0;
s.st_size = 0;
// etc...
s.st_st_ctime = -1;
if(stat(path, &s) != 0) {
// handle error
return;
}
WTF???
Обратите внимание, что мы обрабатываем ошибку сразу же, таким образом, нет никакого вопроса о том, что происходит, если статистика перестала работать.
Если Вы думаете, что инициализация избыточна, это. Моя цель состоит в том, чтобы написать код, который максимально по-человечески читаем. Ненужная инициализация смущает будущего читателя.
Компиляторы C становятся довольно хорошими в ловле использования unitialized переменных, таким образом, опасность этого теперь минимальна.
Не забывайте путем создания "поддельной" инициализации, Вы торгуете одной опасностью - отказывающий при использовании мусора (который приводит к ошибке, которую очень легко найти и зафиксировать) на другом - программа, принимающая неправильные меры на основе поддельного значения (который, приводит к ошибке, которую очень трудно найти). Выбор зависит от приложения. Для некоторых очень важно никогда не отказать. Для большинства лучше поймать ошибку как можно скорее.
Производительность? В наше время? Возможно, назад, когда центральные процессоры достигли 10 МГц, это действительно имело смысл, но сегодня едва проблема. Всегда инициализируйте их.