Эта статья содержит рекламный контент . ( Январь 2024 г. ) |
Парадигма | Мультипарадигмальный : функциональный , императивный , объектно-ориентированный |
---|---|
Разработано | Уолтер Брайт , Андрей Александреску (с 2007 г.) |
Разработчик | Фонд языка D |
Впервые появился | 8 декабря 2001 г ( 2001-12-08 ) | [1]
Стабильный релиз | 2.109.1 [2] / 1 июля 2024 г. ( 1 июля 2024 ) |
Дисциплина печати | Предполагаемый , статический , сильный |
ОС | FreeBSD , Linux , macOS , Windows |
Лицензия | Усиление [3] [4] [5] |
Расширения имени файла | .д [6] [7] |
Веб-сайт | dlang.org |
Основные внедрения | |
DMD ( референтная реализация ), GCC, ГДК, НРС, СРС | |
Под влиянием | |
BASIC , [8] C , C++ , C# , Eiffel , [9] Java , Python , Ruby | |
Под влиянием | |
Genie, MiniD, Qore , Swift , [10] Vala , C++11 , C++14 , C++17 , C++20 , Go , C# , другие | |
D , также известный как dlang , — это многопарадигмальный системный язык программирования , созданный Уолтером Брайтом в Digital Mars и выпущенный в 2001 году. Андрей Александреску присоединился к проектированию и разработке в 2007 году. Хотя он возник как переработка C++ , сейчас D — это совсем другой язык. По мере своего развития он черпал вдохновение из других языков программирования высокого уровня . В частности, на него повлияли Java , Python , Ruby , C# и Eiffel .
Справочник по языку D описывает это следующим образом:
D — это системный язык программирования общего назначения с синтаксисом, похожим на C, который компилируется в машинный код. Он статически типизирован и поддерживает как автоматическое (сборка мусора), так и ручное управление памятью. Программы на D структурированы как модули, которые могут компилироваться отдельно и связываться с внешними библиотеками для создания машинных библиотек или исполняемых файлов. [11]
D несовместим по исходному коду с исходным кодом C и C++ в целом. Однако любой код, который является допустимым как в C, так и в D, должен вести себя одинаково.
Как и в C++, в D есть замыкания , анонимные функции , выполнение функций во время компиляции , диапазоны, встроенные концепции итерации контейнеров и вывод типов . Синтаксисы объявлений, операторов и выражений в D также очень похожи на синтаксисы в C++.
В отличие от C++, D также реализует проектирование по контракту , сборку мусора , массивы первого класса , нарезку массивов , вложенные функции и ленивые вычисления . D использует одиночное наследование в стиле Java с интерфейсами и миксинами, а не множественное наследование в стиле C++ .
D — это язык системного программирования. Как и C++, и в отличие от прикладных языков, таких как Java и C# , D поддерживает низкоуровневое программирование , включая встроенный ассемблер . Встроенный ассемблер позволяет программистам вводить машинно-специфичный ассемблерный код в стандартный код D. Системные программисты используют этот метод для доступа к низкоуровневым функциям процессора , которые необходимы для запуска программ, напрямую взаимодействующих с базовым оборудованием , таким как операционные системы и драйверы устройств . Низкоуровневое программирование также используется для написания кода с более высокой производительностью , чем тот, который был бы создан компилятором .
D поддерживает перегрузку функций и перегрузку операторов . Символы ( функции , переменные , классы ) могут быть объявлены в любом порядке; предварительные объявления не нужны.
В языке D текстовые строки символов представляют собой массивы символов, а массивы в языке D проверяются на выход за пределы границ. [12] В языке D имеются типы первого класса для комплексных и мнимых чисел. [13]
D поддерживает пять основных парадигм программирования :
Императивное программирование в D почти идентично программированию в C. Функции, данные, операторы, объявления и выражения работают так же, как и в C, а библиотека времени выполнения C может быть доступна напрямую. С другой стороны, в отличие от C, foreach
конструкция цикла D позволяет выполнять цикл по коллекции. D также допускает вложенные функции , которые являются функциями, объявленными внутри другой функции, и которые могут обращаться к локальным переменным охватывающей функции .
импортировать std.stdio ; void main () { int multiplier = 10 ; int scaled ( int x ) { return x * multiplier ; } foreach ( i ; 0 .. 10 ) { writefln ( "Привет, мир %d! scaled = %d" , i , scaled ( i )); } }
Объектно-ориентированное программирование в D основано на единой иерархии наследования , где все классы являются производными от класса Object. D не поддерживает множественное наследование; вместо этого он использует интерфейсы в стиле Java , которые сопоставимы с чистыми абстрактными классами C++, и миксины , которые отделяют общую функциональность от иерархии наследования. D также позволяет определять статические и финальные (невиртуальные) методы в интерфейсах.
Интерфейсы и наследование в D поддерживают ковариантные типы для возвращаемых типов переопределенных методов.
D поддерживает переадресацию типов, а также опциональную пользовательскую динамическую диспетчеризацию .
Классы (и интерфейсы) в D могут содержать инварианты , которые автоматически проверяются до и после входа в открытые методы в соответствии с методологией проектирования по контракту .
Многие аспекты классов (и структур) могут быть автоматически проанализированы во время компиляции (форма рефлексивного программирования (рефлексии) с использованием type traits
) и во время выполнения (RTTI / TypeInfo
), чтобы облегчить создание универсального кода или автоматическую генерацию кода (обычно с использованием методов времени компиляции).
D поддерживает такие функциональные возможности программирования , как функциональные литералы , замыкания , рекурсивно-неизменяемые объекты и использование функций высшего порядка . Существует два синтаксиса для анонимных функций, включая многооператорную форму и «сокращенную» нотацию с одним выражением: [14]
int function ( int ) g ; g = ( x ) { return x * x ; }; // длинная запись g = ( x ) => x * x ; // сокращенная запись
Существует два встроенных типа для литералов функций, function
, который является просто указателем на стековую функцию, и delegate
, который также включает указатель на соответствующий стековый фрейм , окружающую «среду», которая содержит текущие локальные переменные. Вывод типа может использоваться с анонимной функцией, в этом случае компилятор создает , delegate
если только он не может доказать, что указатель среды не нужен. Аналогично, чтобы реализовать замыкание, компилятор помещает вложенные локальные переменные в кучу, только если это необходимо (например, если замыкание возвращается другой функцией и выходит из области действия этой функции). При использовании вывода типа компилятор также добавит атрибуты, такие как pure
и , nothrow
к типу функции, если он может доказать, что они применяются.
Другие функциональные возможности, такие как каррирование и общие функции высшего порядка, такие как map , filter и reduce , доступны через стандартные библиотечные модули std.functional
и std.algorithm
.
импорт станд.стдио , станд.алгоритм , станд.диапазон ; void main () { int [] a1 = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]; int [] a2 = [ 6 , 7 , 8 , 9 ]; // должен быть неизменяемым, чтобы разрешить доступ изнутри чистой функции immutable pivot = 5 ; int mySum ( int a , int b ) pure nothrow /* чистая функция */ { if ( b <= pivot ) // ссылка на охватывающую область действия return a + b ; else return a ; } // передача делегата (замыкание) auto result = reduce ! mySum ( chain ( a1 , a2 )); writeln ( "Result: " , result ); // Результат: 15 // передача делегата литерала result = reduce !(( a , b ) => ( b <= pivot ) ? a + b : a )( chain ( a1 , a2 )); writeln ( "Результат: " , result ); // Результат: 15 }
В качестве альтернативы приведенные выше композиции функций можно выразить с помощью унифицированного синтаксиса вызова функций (UFCS) для более естественного чтения слева направо:
auto result = a1.chain ( a2 ) .reduce ! mySum ( ); writeln ( "Результат: " , result ) ; result = a1.chain ( a2 ) .reduce !(( a , b ) => ( b <= pivot ) ? a + b : a )(); writeln ( " Результат : " , result );
Концепции параллельного программирования реализованы в библиотеке и не требуют дополнительной поддержки со стороны компилятора. Однако система типа D и компилятор гарантируют, что совместное использование данных может быть обнаружено и прозрачно управляемо.
импорт std.stdio : writeln ; импорт std.range : iota ; импорт std.parallelism : parallel ; void main () { foreach ( i ; iota ( 11 ). parallel ) { // Тело цикла foreach выполняется параллельно для каждого i writeln ( "processing" , i ); } }
iota(11).parallel
эквивалентно std.parallelism.parallel(iota(11))
использованию UFCS.
Этот же модуль также поддерживает, taskPool
который может использоваться для динамического создания параллельных задач, а также операций map-filter-reduce и fold в диапазонах (и массивах), что полезно в сочетании с функциональными операциями. std.algorithm.map
возвращает лениво вычисляемый диапазон, а не массив. Таким образом, элементы вычисляются каждой рабочей задачей параллельно автоматически.
импорт std.stdio : writeln ; импорт std.algorithm : map ; импорт std.range : iota ; импорт std.parallelism : taskPool ; /* На Intel i7-3930X и gdc 9.3.0: * 5140 мс при использовании std.algorithm.reduce * 888 мс при использовании std.parallelism.taskPool.reduce * * На AMD Threadripper 2950X и gdc 9.3.0: * 2864 мс при использовании std.algorithm.reduce * 95 мс при использовании std.parallelism.taskPool.reduce */ void main () { auto nums = iota ( 1.0 , 1_000_000_000.0 ); auto x = taskPool.reduce ! "a + b" ( 0.0 , map ! "1.0 / (a * a) " ( nums ) ) ; writeln ( "Сумма: " , x ); }
Параллелизм полностью реализован в библиотеке и не требует поддержки со стороны компилятора. Возможны альтернативные реализации и методологии написания параллельного кода. Использование системы типизации D помогает обеспечить безопасность памяти.
импорт std.stdio , std.concurrency , std.variant ; void foo () { bool cont = true ; while ( cont ) { receive ( // Делегаты используются для сопоставления типа сообщения. ( int msg ) => writeln ( "int received: " , msg ), ( Tid sender ) { cont = false ; sender . send (- 1 ); }, ( Variant v ) => writeln ( "huh?" ) // Вариант соответствует любому типу ); } } void main () { auto tid = spawn (& foo ); // создаем новый поток, выполняющий foo() foreach ( i ; 0 .. 10 ) tid . send ( i ); // отправить несколько целых чисел tid.send ( 1.0f ); // отправить число с плавающей точкой tid.send ( " hello " ) ; // отправить строку tid.send ( thisTid ); // отправить структуру ( Tid ) receive (( int x ) => writeln ( "Основной поток получил сообщение: " , x )); }
Метапрограммирование поддерживается с помощью шаблонов, выполнения функций во время компиляции, кортежей и строковых миксинов. Следующие примеры демонстрируют некоторые возможности D во время компиляции.
Шаблоны в D могут быть написаны в более императивном стиле по сравнению с функциональным стилем шаблонов C++. Это обычная функция, которая вычисляет факториал числа:
ulong факториал ( ulong n ) { if ( n < 2 ) вернуть 1 ; иначе вернуть n * факториал ( n - 1 ); }
Здесь демонстрируется использование static if
условной конструкции времени компиляции D для создания шаблона, который выполняет те же вычисления с использованием кода, аналогичного коду функции выше:
шаблон Факториал ( ulong n ) { static if ( n < 2 ) enum Факториал = 1 ; else enum Факториал = n * Факториал !( n - 1 ); }
В следующих двух примерах шаблон и функция, определенные выше, используются для вычисления факториалов. Типы констант не обязательно должны быть указаны явно, поскольку компилятор выводит их типы из правых сторон присваиваний:
enum fact_7 = Факториал !( 7 );
Это пример выполнения функции во время компиляции (CTFE). Обычные функции могут использоваться в постоянных выражениях во время компиляции, если они соответствуют определенным критериям:
enum fact_9 = факториал ( 9 );
Функция std.string.format
выполняет printf
форматирование данных (также во время компиляции, через CTFE), а прагма "msg" отображает результат во время компиляции:
импортировать std.string : format ; pragma ( msg , format ( "7!=%s" , fact_7 ) ); pragma ( msg , format ( " 9!=%s" , fact_9 ));
Строковые миксины, в сочетании с выполнением функции во время компиляции, позволяют генерировать код D с использованием строковых операций во время компиляции. Это может быть использовано для разбора доменно-специфичных языков , которые будут скомпилированы как часть программы:
import FooToD ; // гипотетический модуль, содержащий функцию, которая анализирует исходный код Foo // и возвращает эквивалентный код D void main () { mixin ( fooToD ( import ( "example.foo" ))); }
Память обычно управляется сборкой мусора , но определенные объекты могут быть финализированы немедленно, когда они выходят из области видимости. Это то, что используют большинство программ и библиотек, написанных на D.
В случае, если требуется больший контроль над распределением памяти и лучшая производительность, возможно явное управление памятью с помощью перегруженного оператора new
, путем прямого вызова malloc и free языка C или реализации пользовательских схем распределения (например, в стеке с откатом, распределением в стиле RAII, подсчетом ссылок, общим подсчетом ссылок). Сборку мусора можно контролировать: программисты могут добавлять и исключать диапазоны памяти из наблюдения сборщиком, могут отключать и включать сборщик и принудительно запускать либо генерационный, либо полный цикл сбора. [15] В руководстве приведено множество примеров того, как реализовать различные высокооптимизированные схемы управления памятью, когда сборка мусора в программе неадекватна. [16]
В функциях struct
экземпляры по умолчанию размещаются в стеке, тогда как class
экземпляры по умолчанию размещаются в куче (только со ссылкой на экземпляр класса, находящийся в стеке). Однако это можно изменить для классов, например, используя стандартный шаблон библиотеки std.typecons.scoped
или используя new
for structs и присваивая указатель вместо переменной на основе значения. [17]
В функциях статические массивы (известного размера) размещаются в стеке. Для динамических массивов можно использовать функцию core.stdc.stdlib.alloca
(аналогичную alloca
в C), чтобы разместить память в стеке. Возвращаемый указатель можно использовать (преобразовать) в (типизированный) динамический массив с помощью среза (однако следует избегать изменения размера массива, включая добавление; и по очевидным причинам они не должны возвращаться из функции). [17]
Ключевое scope
слово может использоваться как для аннотирования частей кода, так и переменных и классов/структур, чтобы указать, что они должны быть уничтожены (вызван деструктор) немедленно при выходе из области видимости. То, какая память освобождается, также зависит от реализации и различий между классами и структурами. [18]
std.experimental.allocator
Содержит модульные и компонуемые шаблоны распределителей для создания пользовательских высокопроизводительных распределителей для специальных случаев использования. [19]
SafeD [20]
— это имя, данное подмножеству D, которое может быть гарантированно безопасно для памяти . Функции, отмеченные , @safe
проверяются во время компиляции, чтобы убедиться, что они не используют никаких функций, таких как арифметика указателей и непроверяемые приведения, которые могут привести к повреждению памяти. Любые другие вызываемые функции также должны быть отмечены как @safe
или @trusted
. Функции могут быть отмечены @trusted
для случаев, когда компилятор не может отличить безопасное использование функции, отключенной в SafeD, от потенциального случая повреждения памяти. [21]
Первоначально под знаменами DIP1000 [22] и DIP25 [23] (теперь часть спецификации языка [24] ), D обеспечивает защиту от некоторых некорректных конструкций, связанных со временем жизни данных.
Существующие механизмы в основном работают с параметрами функций и стековой памятью, однако руководство языка программирования заявило о своей амбиции обеспечить более тщательную обработку времен жизни в языке программирования D [25] (под влиянием идей языка программирования Rust ).
В коде @safe проверяется время жизни присваивания, включающего ссылочный тип , чтобы гарантировать, что время жизни присваиваемого больше, чем у назначаемого.
Например:
@safe void test () { int tmp = 0 ; // #1 int * rad ; // #2 rad = & tmp ; // Если порядок объявлений #1 и #2 обратный, это не сработает. { int bad = 45 ; // Время жизни "bad" распространяется только на область действия, в которой оно определено. * rad = bad ; // Это допустимо. rad = & bad ; // Время жизни rad больше, чем bad, поэтому это недопустимо. } }
При применении к параметрам функции, которые имеют тип указателя или ссылки, ключевые слова return и scope ограничивают время существования и использование этого параметра.
Стандарт языка диктует следующее поведение: [26]
Класс хранения | Поведение (и ограничения) параметра с классом хранения |
---|---|
объем | Ссылки в параметре не могут быть экранированы. Игнорируется для параметров без ссылок |
возвращаться | Параметр может быть возвращен или скопирован в первый параметр, но в противном случае не выходит из функции. Такие копии должны не пережить аргумент(ы), из которых они были получены. Игнорируется для параметров без ссылок |
Ниже приведен аннотированный пример.
@безопасный :int * gp ; void thorin ( scope int *); void gloin ( int *); int * balin ( return scope int * p , scope int * q , int * r ) { gp = p ; // Ошибка, p переходит в глобальную переменную gp. gp = q ; // Ошибка, q переходит в глобальную переменную gp. gp = r ; // OK. thorin ( p ); // OK, p не экранируется thorin(). thorin ( q ); // OK. thorin ( r ); // OK. глоин ( р ); // Ошибка, p выходит за пределы globin(). глоин ( q ); // Ошибка, q выходит из globin(). глоин ( р ); // Хорошо, что r экранирует glein(). return p ; // OK. return q ; // Ошибка, невозможно вернуть 'scope' q. return r ; // OK. }
Поддерживается двоичный интерфейс приложения C ( ABI) , а также все основные и производные типы C, что обеспечивает прямой доступ к существующему коду и библиотекам C. Привязки D доступны для многих популярных библиотек C. Кроме того, стандартная библиотека C является частью стандарта D.
В Microsoft Windows D может получить доступ к коду модели компонентных объектов (COM).
При условии надлежащего управления памятью многие другие языки можно смешивать с D в одном двоичном файле. Например, компилятор GDC позволяет связывать и смешивать C, C++ и другие поддерживаемые языковые коды, такие как Objective-C. Код D (функции) также может быть помечен как использующий C, C++, Pascal ABI и, таким образом, передаваться в библиотеки, написанные на этих языках, как обратные вызовы . Аналогично данные могут обмениваться между кодами, написанными на этих языках, обоими способами. Обычно это ограничивает использование примитивными типами, указателями, некоторыми формами массивов, объединений , структур и только некоторыми типами указателей на функции.
Поскольку многие другие языки программирования часто предоставляют API C для написания расширений или запуска интерпретатора языков, D также может напрямую взаимодействовать с этими языками, используя стандартные привязки C (с тонким файлом интерфейса D). Например, существуют двунаправленные привязки для таких языков, как Python , [27] Lua [28] [29] и других языков, часто использующих методы генерации кода во время компиляции и отражения типов во время компиляции.
Для кода D, обозначенного как extern(C++)
, указаны следующие характеристики:
Пространства имен C++ используются с помощью синтаксиса extern(C++, namespace)
, где namespace — это имя пространства имен C++.
Сторона C++
импорт стандартный ; класс Base { public : virtual void print3i ( int a , int b , int c ) = 0 ; }; класс Производный : public Base { public : int field ; Производный ( int field ) : field ( field ) {} void print3i ( int a , int b , int c ) { std :: println ( "a = {}" , a ); std :: println ( "b = {}" , b ); std :: println ( "c = {}" , c ); } int mul ( int factor ); }; int Derived::mul ( int factor ) { return field * factor ; } Производный * createInstance ( int i ) { return new Производный ( i ); } void deleteInstance ( Производный *& d ) { удалить d ; d = 0 ; }
Сторона D
extern ( C ++) { абстрактный класс Base { void print3i ( int a , int b , int c ); } класс Derived : Base { int field ; @disable this (); override void print3i ( int a , int b , int c ); final int mul ( int factor ); } Производный createInstance ( int i ); void deleteInstance ( ref Производный d ); } void main ( ) { import std.stdio ; auto d1 = createInstance ( 5 ) ; writeln ( d1.field ) ; writeln ( d1.mul ( 4 ) ) ; База b1 = d1 ; b1 . print3i ( 1 , 2 , 3 ); deleteInstance ( d1 ); assert ( d1 is null ); auto d2 = createInstance ( 42 ) ; writeln ( d2.field ) ; deleteInstance ( d2 ); утвердить ( d2 равен нулю ); }
Язык программирования D имеет официальное подмножество, известное как « Better C ». [30] Это подмножество запрещает доступ к функциям D, требующим использования библиотек времени выполнения, отличных от C.
Включенный с помощью флагов компилятора "-betterC" в DMD и LDC и "-fno-druntime" в GDC, Better C может вызывать только код D, скомпилированный с тем же флагом (и связанный код, отличный от D), но код, скомпилированный без параметра Better C, может вызывать код, скомпилированный с ним: однако это приведет к несколько разному поведению из-за различий в том, как C и D обрабатывают утверждения.
core.thread
)core.sync
Уолтер Брайт начал работать над новым языком в 1999 году. D был впервые выпущен в декабре 2001 года [1] и достиг версии 1.0 в январе 2007 года. [31] Первая версия языка (D1) была сосредоточена на императивной, объектно-ориентированной и метапрограммистской парадигмах, [32] аналогичной C++.
Некоторые члены сообщества D, недовольные Phobos, официальной средой выполнения и стандартной библиотекой D , создали альтернативную среду выполнения и стандартную библиотеку под названием Tango. Первое публичное объявление о Tango появилось через несколько дней после выпуска D 1.0. [33] Tango принял другой стиль программирования, охватывающий ООП и высокую модульность. Будучи проектом, управляемым сообществом, Tango был более открыт для вкладов, что позволило ему развиваться быстрее, чем официальная стандартная библиотека. В то время Tango и Phobos были несовместимы из-за разных API поддержки среды выполнения (сборщик мусора, поддержка потоков и т. д.). Это сделало невозможным использование обеих библиотек в одном проекте. Существование двух библиотек, обе из которых широко использовались, привело к значительным спорам из-за того, что некоторые пакеты использовали Phobos, а другие — Tango. [34]
В июне 2007 года была выпущена первая версия D2. [35] Начало разработки D2 ознаменовало стабилизацию D1. Первая версия языка была помещена в обслуживание, получая только исправления и исправления ошибок реализации. D2 внес критические изменения в язык, начиная с его первой экспериментальной системы const . Позже D2 добавил множество других языковых функций, таких как замыкания , чистота и поддержка функциональных и параллельных парадигм программирования. D2 также решил проблемы стандартной библиотеки, отделив среду выполнения от стандартной библиотеки. Завершение порта D2 Tango было объявлено в феврале 2012 года. [36]
Выход книги Андрея Александреску «Язык программирования D» 12 июня 2010 года ознаменовал стабилизацию D2, который сегодня обычно называют просто «D».
В январе 2011 года разработка D перешла с багтрекера/патч-отправки на GitHub . Это привело к значительному увеличению вклада в компилятор, среду выполнения и стандартную библиотеку. [37]
В декабре 2011 года Андрей Александреску объявил, что D1, первая версия языка, будет прекращена 31 декабря 2012 года. [38] Окончательный релиз D1, D v1.076, состоялся 31 декабря 2012 года. [39]
Код для официального компилятора D, компилятора Digital Mars D Уолтера Брайта, изначально был выпущен под пользовательской лицензией , подпадающей под категорию исходного кода , но не соответствующей определению открытого исходного кода . [40] В 2014 году интерфейс компилятора был повторно лицензирован как открытый исходный код по лицензии Boost Software License . [3] Этот повторно лицензированный код исключал бэкэнд, который был частично разработан в Symantec . 7 апреля 2017 года весь компилятор стал доступен под лицензией Boost после того, как Symantec дала разрешение повторно лицензировать и бэкэнд. [4] [41] [42] [43] 21 июня 2017 года язык D был принят для включения в GCC. [44]
Большинство современных реализаций D компилируются непосредственно в машинный код .
Готовые к использованию компиляторы:
Игрушечные и экспериментальные компиляторы:
Используя указанные выше компиляторы и наборы инструментов, можно компилировать программы на D для множества различных архитектур, включая IA-32 , amd64 , AArch64 , PowerPC , MIPS64 , DEC Alpha , Motorola m68k , SPARC , s390 , WebAssembly . Основными поддерживаемыми операционными системами являются Windows и Linux , но различные компиляторы также поддерживают Mac OS X , FreeBSD , NetBSD , AIX , Solaris/OpenSolaris и Android , как в качестве хоста, так и в качестве цели, или и то, и другое. Цель WebAssembly (поддерживаемая через LDC и LLVM) может работать в любой среде WebAssembly, например, в современном веб-браузере ( Google Chrome , Mozilla Firefox , Microsoft Edge , Apple Safari ) или в выделенных виртуальных машинах Wasm.
Редакторы и интегрированные среды разработки (IDE), поддерживающие подсветку синтаксиса и частичное завершение кода для языка, включают SlickEdit , Emacs , vim , SciTE , Smultron , Zeus, [56] и Geany среди прочих. [57]
Существуют среды разработки D с открытым исходным кодом для Windows , некоторые из них написаны на D, например Poseidon, [70] D-IDE, [71] и Entice Designer. [72]
Приложения D можно отлаживать с помощью любого отладчика C/C++, например GNU Debugger (GDB) или WinDbg , хотя поддержка различных функций языка, специфичных для D, крайне ограничена. В Windows программы D можно отлаживать с помощью Ddbg или инструментов отладки Microsoft (WinDBG и Visual Studio), после преобразования отладочной информации с помощью cv2pdb. Отладчик ZeroBUGS, архивированный 23 декабря 2017 г. на Wayback Machine , для Linux имеет экспериментальную поддержку языка D. Ddbg можно использовать с различными IDE или из командной строки; ZeroBUGS имеет собственный графический пользовательский интерфейс (GUI).
DustMite — это инструмент для минимизации исходного кода D, полезный при поиске проблем с компилятором или тестами. [73]
dub — популярный менеджер пакетов и сборок для приложений и библиотек D, часто интегрируемый в поддержку IDE. [74]
Этот раздел, возможно, содержит оригинальные исследования . ( Сентябрь 2020 г. ) |
Этот пример программы выводит свои аргументы командной строки. main
Функция является точкой входа программы D и args
представляет собой массив строк, представляющих аргументы командной строки. A string
в D — это массив символов, представленный как immutable(char)[]
.
импорт std.stdio : writefln ; void main ( строка [] аргументы ) { foreach ( i , arg ; args ) writefln ( "args[%d] = '%s'" , i , arg ); }
Оператор foreach
может выполнять итерацию по любой коллекции. В этом случае он создает последовательность индексов ( i
) и значений ( arg
) из массива args
. Индекс i
и значение arg
имеют свои типы, выведенные из типа массива args
.
Ниже показаны несколько возможностей D и компромиссы дизайна D в короткой программе. Она перебирает строки текстового файла с именем words.txt
, который содержит разные слова в каждой строке, и выводит все слова, которые являются анаграммами других слов.
импорт std.stdio , std.algorithm , std.range , std.string ; пустая основная () { dstring [] [ dstring ] подпись2слова ; foreach ( dchar [] w ; строки ( Файл ( "words.txt" ))) { w = w . chomp (). toLower (); неизменяемая сигнатура = w.dup.sort ( ) . release ( ) . idup ; подпись2слова [ подпись ] ~ = w.idup ; } foreach ( слова ; подпись2слова ) { если ( слова . длина > 1 ) writeln ( слова.присоединиться ( "" ) ) ; }}
signature2words
— встроенный ассоциативный массив, который сопоставляет ключи dstring (32-бит / char) с массивами dstrings. Он похожdefaultdict(list)
на .lines(File())
возвращает строки лениво, с новой строкой. Затем его нужно скопировать с , idup
чтобы получить строку, которая будет использоваться для значений ассоциативного массива ( idup
свойство массивов возвращает неизменяемый дубликат массива, что требуется, поскольку dstring
тип на самом деле immutable(dchar)[]
). Встроенные ассоциативные массивы требуют неизменяемых ключей.~=
добавляет новую строку dstring к значениям соответствующего динамического массива.toLower
, join
и chomp
являются строковыми функциями, которые D позволяет использовать с синтаксисом метода. Названия таких функций часто похожи на строковые методы Python. преобразует toLower
строку в нижний регистр, join(" ")
объединяет массив строк в одну строку, используя один пробел в качестве разделителя, и chomp
удаляет новую строку из конца строки, если она присутствует. w.dup.sort().release().idup
более читабельна, но эквивалентна, release(sort(w.dup)).idup
например, . Эта функция называется UFCS (Uniform Function Call Syntax) и позволяет расширять любые встроенные или сторонние типы пакетов функциональностью, подобной методу. Стиль написания кода, подобный этому, часто называют конвейером ( особенно когда используемые объекты вычисляются лениво, например, итераторы/диапазоны) или интерфейсом Fluent .sort
функция std.algorithm, которая сортирует массив на месте, создавая уникальную сигнатуру для слов, которые являются анаграммами друг друга. release()
Метод возвращаемого значения sort()
удобен для сохранения кода в виде одного выражения.foreach
перебирает значения ассоциативного массива и может определить тип words
.signature
присваивается неизменяемой переменной, ее тип выводится.dchar[]
используется вместо обычного UTF-8, char[]
иначе sort()
отказывается сортировать. Есть более эффективные способы написать эту программу, используя только UTF-8.Известные организации, которые используют язык программирования D для своих проектов, включают Facebook , [75] eBay , [76] и Netflix . [77]
D успешно использовался для игр класса ААА , [78] интерпретаторов языков, виртуальных машин, [79] [80] ядра операционной системы , [ 81] программирования графических процессоров , [82] веб-разработки , [83] [84] численного анализа , [85] приложений с графическим интерфейсом пользователя , [86] [87] системы информирования пассажиров , [88] машинного обучения, [89] обработки текста, веб-серверов и серверов приложений, а также исследований.
Печально известная северокорейская хакерская группа, известная как Lazarus, использовала уязвимость CVE-2021-44228, также известную как « Log4Shell », для развертывания трех семейств вредоносных программ, написанных на DLang. [90]
Отсутствие прозрачности, гибкости и предсказуемости в процессе исправления известных недостатков и ошибок, а также сложность внесения мелких и крупных изменений в язык D, неминуемо описаны в статье блога [91] бывшим участником. Описанное там явное разочарование привело к форку OpenD [92] 1 января 2024 года.