D语言
特性
D的设计来自实际的C++用法的经验教训,而不是从理论的角度。D沿用了很多C/C++观念,同时摒弃了一些概念,因此D并不完全兼容C/C++代码。D实现了C++的功能,实现了契约式设计(design by contract)、单元测试、真正的模块性、自动化内存管理(垃圾回收)、第一类数组(first class array)、关联数组、动态数组、数组切片、嵌套函数(嵌套函数)、内部类别、闭包的限制形式、匿名函数、编译时期函数运行、惰性计算以及革新的模板语法。D保有C++的性能以进行低级程序设计,并加入完整的内联汇编器支持。C++的多重继承改以Java单继承与接口混合的风格取代。D的宣告、语句和表达式语法几乎和C++一样。
内联汇编器(inline assembler)象征了D和Java、C#等应用程序语言的不同。内联汇编器让程序员输入机器特定的汇编语言码,如同标准D代码—通常由系统程序员使用的技术,以访问处理器的低级功能,直接以硬件下的界面运行程序,如操作系统以及驱动程序。
D内置支持文件注解,不过目前为止,只有Digital Mars实现版本有提供文件产生器。
程序设计范型
D支持三种主要的程序设计泛型—指令式、面向对象以及元程序设计。
指令式
指令式程序设计几乎和C一样。函数、数据、语句、宣告以及表达式的运作就如同C一般,且可直接访问C运行时期程序库。
面向对象
在D里面的面向对象程序设计,是以单继承分层结构,配合所有类别衍伸自类别对象为基础。多重继承可使用界面(界面很像C++的抽象类别)。
元程序设计
以模板组合、编译时期函数运行、多元组以及字符串混合来支持元程序设计。
内存管理
内存通常以垃圾回收管理,不过当这些对象超出作用域时,可立即结束指定的对象。还是可以使用重载运算符new和delete,以及简单的直接调用C的malloc函数和free函数以进行显示的内存管理。垃圾回收可禁用个别的对象或事件,以健全整个程序,如果在内存管理上有更多的控制,则更为理想。当垃圾回收在程序中有所不足时,手册还提供许多如何实现不同的高度最优化内存管理方案的示例。
与其它系统的相互作用
支持C的应用程序二进制接口(ABI),以及C的基本和衍伸类型,就能直接访问现有的C代码以及程序库。C的标准库也是D标准的一部分。除非你使用非常清楚的名字空间,它可以稍微散乱的访问,因为它散布遍及于D模块—不过纯粹的D标准库也通常够用,除非要与C代码接合。
并未完整支持C++的ABI,尽管D可以访问写给C ABI的C++代码,且可访问C++COM(组件对象模型)代码。D语法分析器了解外部(C++)调用约定,以链接C++对象,不过它只实现在D 2.0。
D 2.0
D 2.0,D 新一代版本,D2.0与D1.0是不兼容的,类似Python2和Python3的区别。目前D2已经稳定下来。其中一部分特性包括支持强制常数正确性(const-correctness),以及有限的支持链接以C++编写的代码。
实现
目前D直接编译成原生码以高效运行。
D语言1.x版本已稳定,不再功能变更或扩展,2.0版本是其正式版本,不完全兼容旧版本的语言和编译器。官方编译器由Walter Bright定义语言本身。
DMD编译器:Digital Mars D编译器,由Walter Bright编写的官方D编译器。编译器前端的授权许可为Artistic License和GNUGPL两者;前端的源代码连同编译器运行码一起发布。编译器的后端则是私有的。
GDC:D 1.0编译器,以DMD编译器前端,以及GCC后端所组成。
LDC:D 2.0编译器,以DMD编译器前端,以及LLVM后端所组成。LDC的官方版本已不支持D1.0,但其分支版本依然支持D1.0 。
问题和争议
运算符重载
D运算符重载在一定程度上不如C++强大。简单的例子是 opIndex ,它不允许返回引用。这使像是 obj[i] = 5; 的赋值不可能存在。D的解决方法是 opIndexAssign 运算符,它只用于这种特殊情况。此外,C++返回参考的方法允许返回类型的重载赋值运算符的用法。这在目前的D还不可能做到。D 2.0将会引入 opIndexLvalue 修正 - 类似运算符重载和 opIndexAssign 。
低功的结构
结构在D之中是一种朴素旧式数据的类型,不过也可像变量一样包含方法。这对有意轻量化的建构而言相当实用,如矩阵或向量,这些不需要完整的D类别功能(以及体积)。然而,D结构没有构造函数和析构函数。构造函数可用静态 opCall 运算符部分取代,不过它没有适合的析构函数等价物。此外,结构不允许继承,这会是有益的设计,如诡异循环模板模式(curiously recurring template pattern)的使用。
标准库中缺乏功能
D的标准库称作Phobos,且时常被认为过分简单。tango项目编写另一个标准库试图修正这一部分,不过phobos和tango目前由于不同的对象类别实现(导致垃圾回收困难)而互不兼容。存在两种事实上的标准库可能导致更大的问题,部分软件使用phobos,而其它软件使用tango。
缺乏明确的目标
D经常限于“修正并改进的C++”。这会导致过分强调功能,这起因于加入新功能只是因为他们认为有用。举个例子, 关系数组可简单的以标准库实现。
未完成对共享/动态库的支持
Unix的ELF共享库使用GDC编译器支持到某个程度。在Windows系统中,目前还不支持DLL。因此现阶段不可能编写插件。不像C++,经由C函数发送的D对象将不能运作,因为这将会与垃圾回收器产生冲突。
示例
示例1
这个示例程序会输出它自己的命令行参数。 main 函数是D程序的进入点, args 是表示为字符串数组的命令行参数。在D语言里的字符串是一个字符数组,以 char[] 表示。新版本中定义 string 为 char[] 的别名,不过别名定义必须与旧版本兼容。
importstd.stdio;// 以使用writefln()aliaschar[]string;// 以相容舊的編譯器;新的編譯器中已隱含定義intmain(string[]args){foreach(i,a;args)writefln("args[%d] = "%s"",i,a);return0;}
foreach 语法可迭代所有的集合,在本例中,它从 args 数组生成索引( i )和值( a )的序列。索引 i 和值 a 的类型会从 args 数组的类型推断。
示例2
本例使用关系数组创建更复杂的数据结构。
importstd.stdio;// 以使用writefln()aliaschar[]string;// 以相容舊的編譯器;新的編譯器中已隱含定義intmain(string[]args){// 宣告以字串鍵和字串陣列作為資料的關聯陣列string[][string]container;// 將人們加入到容器中,並讓他們攜帶一些項目container["Anya"]~="scarf";container["Dimitri"]~="tickets";container["Anya"]~="puppy";// 迭代容器中所有的人//Iterate over all the persons in the containerforeach(stringperson,string[]items;container)display_item_count(person,items);return0;//完成}voiddisplay_item_count(stringperson,string[]items){writefln(person," is carrying ",items.length," items.");}
示例3
本例繁多的注解显示出D语言与C++ 的不同之处,以及仍然保留的方面。
#!/usr/bin/dmd-run/* 支援sh風格的script語法!*//* D語言的Hello World * 進行編譯: * dmd hello.d * 或進行最佳化: * dmd -O -inline -release hello.d * 或產生文件: * dmd hello.d -D */importstd.stdio;// 參照常用的I/O例行工作。aliaschar[]string;// 以相容舊的編譯器;新的編譯器中已隱含定義intmain(string[]args){// "writefln" (寫入-格式化-行,Write-Formatted-Line)即型態安全的「printf」writefln("Hello World, "// 自動連結的字串文字"Reloaded");// 字串即字元的動態陣列「char[]」,別名為「string」// 自動的型態推斷,以及內建的foreachforeach(argc,argv;args){autocl=newCmdLin(argc,argv);// 支援OOPwritefln(cl.argnum,cl.suffix," arg: %s",cl.argv);// 使用者定義的類別屬性。deletecl;// 垃圾回收或顯示的記憶體管理——由你自己選擇}// 巢狀結構、類別和函式structspecs{// 所有的變數會在執行時期自動初始化為0intcount,allocated;// 不過你可選擇避開陣列的初始化int[10000]bigarray=void;}specsargspecs(string[]args)// 可選用的(內建)函式契約。in{assert(args.length>0);// 內建assert}out(result){assert(result.count==CmdLin.total);assert(result.allocated>0);}body{specs*s=newspecs;// 不需要「->」s.count=args.length;// 「length」屬性是元素的數量。s.allocated=typeof(args).sizeof;// 原生型態內建的屬性foreach(arg;args)s.allocated+=arg.length*typeof(arg[0]).sizeof;return*s;}// 內建字串和普通的字串操作,例如「~」是連結。stringargcmsg="argc = %d";stringallocmsg="allocated = %d";writefln(argcmsg~", "~allocmsg,argspecs(args).count,argspecs(args).allocated);return0;}/** * 儲存單獨命令列參數 */classCmdLin{private{int_argc;string_argv;statint_totalc;}public:/** * 物件的建構子。 * 參數: * argc = 參數的序列計數。 * argv = 參數內文。 */this(intargc,stringargv){_argc=argc+1;_argv=argv;_totalc++;}~this()// 物件的解構子{// 本例中不做任何事。}intargnum()// 屬性,可返回參數數目{return_argc;}stringargv()// 屬性,可返回參數內文{return_argv;}wstringsuffix()// 屬性,可返回序數後綴{wstringsuffix;// 內建Unicode字串(UTF-8,UTF-16,UTF-32)switch(_argc){case1:suffix="st";break;case2:suffix="nd";break;case3:suffix="rd";break;default:// "default" is mandatory with "-w" compile switch.suffix="th";}returnsuffix;}/** * 靜態屬性,如同在C++ 或Java中, * 適用於類別物件,而不是實體。 * 返回:己加入的命令列參數總數。 */statictypeof(_totalc)total(){return_totalc;}// 類別不變量,任何方法在執行之後,這些必須為真。invariant(){assert(_argc>0);assert(_totalc>=_argc);}}
示例4
本例显示出一部分D语言强大的编译时期特性。
/* * D語言裡的模板比C++ 的要更加強大。 * 在此可以看到使用static if(D的編譯時期條件建構)簡單的建構出階乘模板。 */templateFactorial(ulongn){staticif(n<=1)constFactorial=1;elseconstFactorial=n*Factorial!(n-1);}/* * 這裡有一個正規的函式,可完成同樣的計算。 * 注意它們有多麼的相似。 */ulongfactorial(ulongn){if(n<=1)return1;elsereturnn*factorial(n-1);}/* * 終於,我們可以計算我們的階乘。注意,我們不需要去 * 明確的指定我們的常數的型態:編譯器有足夠的智能為 * 我們填充空白,因為它早已知道賦值中右手邊的型態。 */constfact_7=Factorial!(7);/* * 這是編譯時期函式評估的範例:普通函式可用於常數、 * 編譯時期表達式,假若它們滿足一定的條件。 */constfact_9=factorial(9);/*在此我們可以看到多麼強大的D我們使用 * std.metastrings.Format模板完成型態安全的printf * 資料格式化,並使用message pragma顯示計算結果。 */importstd.metastrings;pragma(msg,Format!("7! = %s",fact_7));pragma(msg,Format!("9! = %s",fact_9));/* * 完成任務後,我們可以強制停止編譯。這樣的程式需是 * 從未實際編譯成可執行檔! */staticassert(false,"My work here is done.");
免责声明:以上内容版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。感谢每一位辛勤著写的作者,感谢每一位的分享。
- 有价值
- 一般般
- 没价值