Понимание шаблонов в D
Я учу себя "D", и у меня возник, что может показаться основным для некоторых, вопрос относительно шаблонов. Например, статья, которую я сейчас читаю (см. Нижнюю часть этого поста), содержит следующий код:
int foo(int x)
{
return x;
}
string foo(string x)
{
return x;
}
void main()
{
assert(foo(12345) == 12345);
assert(foo("hello") == "hello");
}
Очевидно, что этот конкретный фрагмент менее элегантен, и шаблон исключит повторение:
foo(T)(T x)
{
return x;
}
void main()
{
assert(foo!(int)(12345) == 12345);
assert(foo!(string)("hello") == "hello");
}
Второй пример довольно прост, так как мы просто возвращаем переданное значение. Моя путаница возникает из-за того, что функция, как бы она ни была шаблонной, по-прежнему ограничена одним типом значений, поскольку я не могу легко представить строку и целочисленное значение, имеющие много общего. Следовательно, должен ли программист проверять тип передаваемой переменной, а затем писать код для отдельной обработки строк или целых чисел? Действительно ли создание большого функционального тела действительно более эффективно? Я понимаю, что мое незнание шаблонов очевидно. Отсюда и мой вопрос:)
2 ответа
Буквальное определение "шаблона" - это "то, что служит моделью для копирования другими", и именно это делает компилятор. Для каждого типа (string и int в вашем случае) он копирует функцию шаблона и создает специализированную функцию во время компиляции.
Во время выполнения шаблон не требуется, поэтому его можно выбросить после компиляции. В скомпилированном бинарном файле есть две функции foo!(int)
а также foo!(string)
,
Предполагается ли, что программист проверит тип передаваемой переменной, а затем напишет код для обработки случаев строки или целого числа отдельно?
Это зависит от. Иногда вы хотите сделать это. Например, для оптимизации производительности. Иногда вам не нужно делать это и писать общие функции.
Действительно ли создание большого функционального тела действительно более эффективно?
Иногда. Если нет, то не делай этого. Например, вы можете написать один общий find
функция, которая работает с массивами, связанными списками и тому подобным.
Шаблоны - это повторно используемый код для типов, которые вы хотите обрабатывать одинаково. Так что они, вероятно, не тот инструмент, если вы хотите "обрабатывать случаи строки или целого числа отдельно".
В качестве примера возьмем произвольный контейнер, который содержит T элементов. Хотя string и int не имеют много общего, вы сможете создать контейнер для каждого из них.
Другим примером являются математические векторы, где вы можете указать используемый тип. Вы можете указывать математические функции, не ограничивая себя одним типом, и они даже будут работать с пользовательскими типами, если у них перегружены необходимые операторы.