D 语言入门指南:从零开始掌握高效编程 – wiki基地


D语言入门指南:从零开始掌握高效编程

D语言,作为一种多范式系统级编程语言,旨在结合C++的强大性能和Rust的内存安全特性,同时提供Python和Java的现代语言便利性。它由Walter Bright于2001年创建,并在不断发展中,为开发者提供了一个兼具速度、控制力与开发效率的优秀选择。

如果你正在寻找一种能够编写高性能应用、系统级工具,同时又能享受现代语言特性的编程语言,那么D语言绝对值得你深入了解。本指南将带你从零开始,逐步掌握D语言的核心概念和高效编程技巧。

第一部分:初识D语言

1. D语言的特性与优势

D语言的设计哲学是“兼收并蓄,择优而取”。它融合了多种编程语言的优点,使其在多个领域都表现出色:

  • 高性能: 与C++类似,D语言直接编译为机器码,没有虚拟机开销,提供底层内存访问和直接操作硬件的能力。
  • 内存安全: 虽然不如Rust那般强制,但D提供了GC(垃圾回收)和@safe D等机制,帮助开发者编写更安全的代码,减少内存泄漏和访问错误。同时,它也支持手动内存管理。
  • 现代语言特性: 提供了如闭包、匿名函数、元编程(Compile-Time Function Execution, CTFE)、单元测试内置支持、模块化导入、协程(fibers)等现代高级语言特性。
  • 编译速度: D语言的编译器(DMD)以其卓越的编译速度而闻名,这大大提升了开发迭代效率。
  • C/C++兼容性: 可以直接调用C函数和部分C++函数,并使用C头文件,方便与现有C/C++代码库集成。
  • 多范式支持: 支持面向对象、泛型编程、函数式编程和命令式编程等多种范式。

2. D语言的应用场景

D语言适用于多种场景:

  • 系统编程: 操作系统组件、驱动、嵌入式系统。
  • 游戏开发: 需要高性能和低延迟的场景。
  • 科学计算与高性能计算: 利用其速度和并行特性。
  • Web后端: 作为高效的API服务或Web应用后端。
  • 工具开发: CLI工具、脚本等。

第二部分:环境搭建

开始D语言编程的第一步是搭建开发环境。

1. 安装D编译器

D语言有多个编译器实现:

  • DMD (Digital Mars D Compiler): 官方参考编译器,编译速度最快。
  • GDC (GCC D Compiler): 基于GCC后端,提供优秀的优化和广泛的平台支持。
  • LDC (LLVM D Compiler): 基于LLVM后端,同样提供优秀的优化和跨平台能力。

推荐初学者使用DMD,因为它安装简单且编译速度快。

Windows:
下载DMD安装包,按照指示安装即可。或者使用Chocolatey包管理器:
choco install dmd

macOS:
使用Homebrew:
brew install dmd

Linux:
大多数发行版都有DMD包,例如在Ubuntu/Debian上:
sudo apt update
sudo apt install dmd

安装完成后,可以在终端运行 dmd --version 来验证是否安装成功。

2. 安装构建工具(Dub)

D语言的官方包管理器和构建工具是Dub。它类似于Node.js的npm或Rust的Cargo,用于管理项目依赖、编译和运行D程序。Dub通常会随DMD一起安装,如果没有,可以单独安装。

验证Dub是否安装成功:dub --version

3. 配置IDE/编辑器

为了提升开发体验,推荐配置一款支持D语言的IDE或文本编辑器:

  • VS Code: 配合 code-d 插件(或 serve-d),提供语法高亮、自动补全、诊断、调试等功能。这是目前最流行和推荐的选择。
  • Vim/NeoVim: 配合 vim-d 插件。
  • Emacs: 配合 d-mode 插件。
  • IntelliJ IDEA: 配合 DLanguage 插件。

第三部分:D语言基础语法

让我们通过一些基础代码示例来了解D语言的语法。

1. 你的第一个D程序:Hello World

创建一个名为 hello.d 的文件:

“`d
import std.stdio; // 导入标准输入输出模块

void main() // 程序入口点
{
writeln(“Hello, D Language!”); // 打印一行文本到控制台
}
“`

编译并运行:
使用DMD编译:dmd hello.d
这会生成一个可执行文件(在Windows上是hello.exe,在Linux/macOS上是hello)。
运行:./hello (Linux/macOS) 或 hello.exe (Windows)

使用Dub运行(推荐用于项目):
创建一个新项目:dub init my_hello_app
进入项目目录:cd my_hello_app
编辑 source/app.d 文件为上述 “Hello World” 代码。
运行:dub run
Dub会自动编译并运行你的程序。

2. 变量与数据类型

D语言是静态类型语言,但支持类型推断(auto 关键字)。

“`d
void main()
{
// 基本数据类型
int age = 30; // 整型
double salary = 50000.75; // 双精度浮点型
bool isActive = true; // 布尔型
char initial = ‘J’; // 字符型 (UTF-8编码)
string name = “Alice”; // 字符串 (const(char)[]),实际上是不可变的UTF-8字节数组

// 类型推断
auto count = 100; // 推断为 int
auto price = 99.99f; // 推断为 float (f后缀表示单精度)

// 常量
const int MAX_VALUE = 1000;
immutable string GREETING = "Hello"; // 不可变变量,一旦赋值不能改变

// 打印变量
import std.stdio;
writeln("Name: ", name, ", Age: ", age);
writeln("Salary: ", salary, ", Active: ", isActive);
writeln("Count: ", count, ", Price: ", price);
writeln("Max Value: ", MAX_VALUE, ", Greeting: ", GREETING);

}
“`

3. 运算符

D语言支持常见的算术、比较、逻辑、位和赋值运算符。

“`d
void main()
{
int a = 10, b = 3;

// 算术运算符
writeln("a + b = ", a + b); // 13
writeln("a - b = ", a - b); // 7
writeln("a * b = ", a * b); // 30
writeln("a / b = ", a / b); // 3 (整型除法)
writeln("a % b = ", a % b); // 1 (取模)

// 比较运算符
writeln("a > b is ", a > b);     // true
writeln("a == b is ", a == b);   // false
writeln("a != b is ", a != b);   // true

// 逻辑运算符
bool x = true, y = false;
writeln("x && y is ", x && y);   // false (逻辑与)
writeln("x || y is ", x || y);   // true  (逻辑或)
writeln("!x is ", !x);         // false (逻辑非)

}
“`

4. 控制流

  • if-else

    d
    void main()
    {
    int score = 85;
    if (score >= 90) {
    writeln("Excellent!");
    } else if (score >= 60) {
    writeln("Pass.");
    } else {
    writeln("Fail.");
    }
    }

  • switch

    d
    void main()
    {
    int day = 3;
    switch (day) {
    case 1: writeln("Monday"); break;
    case 2: writeln("Tuesday"); break;
    case 3: writeln("Wednesday"); break;
    default: writeln("Another day"); break;
    }
    }

  • for 循环

    “`d
    void main()
    {
    for (int i = 0; i < 5; i++) {
    writeln(“Loop iteration: “, i);
    }

    // 范围for循环(foreach)
    int[] numbers = [10, 20, 30, 40];
    foreach (num; numbers) {
        writeln("Number: ", num);
    }
    
    // 带索引的范围for循环
    foreach (i, num; numbers) {
        writeln("Index ", i, ": ", num);
    }
    

    }
    “`

  • while/do-while 循环

    “`d
    void main()
    {
    int i = 0;
    while (i < 3) {
    writeln(“While loop: “, i);
    i++;
    }

    int j = 0;
    do {
        writeln("Do-while loop: ", j);
        j++;
    } while (j < 3);
    

    }
    “`

5. 函数

“`d
// 无参数无返回值
void sayHello()
{
writeln(“Hello from a function!”);
}

// 带参数无返回值
void greet(string name)
{
writeln(“Hello, “, name, “!”);
}

// 带参数带返回值
int add(int a, int b)
{
return a + b;
}

// 可选参数(默认值)
int multiply(int a, int b = 2)
{
return a * b;
}

// 命名参数 (调用时可以显式指定参数名)
void printInfo(string name, int age)
{
writeln(“Name: “, name, “, Age: “, age);
}

void main()
{
sayHello();
greet(“Darth Vader”);
int sum = add(5, 3);
writeln(“Sum: “, sum); // 8

writeln("Multiply (default): ", multiply(7)); // 14
writeln("Multiply (custom): ", multiply(7, 3)); // 21

// 命名参数调用
printInfo(age: 25, name: "Leia Organa");

}
“`

6. 数组与切片

D语言的数组分为静态数组(编译时大小固定)和动态数组(运行时大小可变)。切片是动态数组的视图。

“`d
void main()
{
// 静态数组
int[5] staticArray = [1, 2, 3, 4, 5];
writeln(“Static Array: “, staticArray);
writeln(“First element: “, staticArray[0]);

// 动态数组
int[] dynamicArray; // 初始为空
dynamicArray ~= 10; // 追加元素
dynamicArray ~= [20, 30]; // 追加多个元素
writeln("Dynamic Array: ", dynamicArray);
writeln("Length: ", dynamicArray.length);

dynamicArray.length = 5; // 改变长度,新元素默认初始化为0
writeln("Resized Array: ", dynamicArray);

// 数组切片
int[] slice = dynamicArray[1..3]; // 包含索引1和2,不包含3
writeln("Slice: ", slice); // [20, 30]

// 遍历数组
foreach (item; dynamicArray) {
    // ...
}

}
“`

7. 关联数组(哈希表/字典)

“`d
void main()
{
// 键类型为string,值类型为int的关联数组
int[string] grades;
grades[“Alice”] = 95;
grades[“Bob”] = 88;
grades[“Charlie”] = 72;

writeln("Bob's grade: ", grades["Bob"]);

// 检查键是否存在
if ("Alice" in grades) { // 'in' 运算符返回指向值的指针或null
    writeln("Alice is in the grades.");
}

// 遍历关联数组
foreach (name, grade; grades) {
    writeln(name, ": ", grade);
}

}
“`

第四部分:深入D语言特性

1. 模块与包

D语言使用模块和包来组织代码。每个 .d 文件就是一个模块。

“`d
// mymodule.d
module mypackage.mymodule; // 定义模块的包路径

import std.stdio;

void saySomething()
{
writeln(“This is from mymodule.”);
}
“`

“`d
// app.d
import mypackage.mymodule; // 导入模块

void main()
{
mypackage.mymodule.saySomething(); // 通过完整路径调用
// 或者可以使用 import mypackage.mymodule : saySomething; 仅导入特定符号
// saySomething();
}
“`

2. 类与结构体(面向对象)

D语言支持面向对象编程。

“`d
// class Animal
class Animal
{
string name;
this(string n) // 构造函数
{
this.name = n;
}
void speak() // 成员方法
{
writeln(name, ” makes a sound.”);
}
}

// 派生类 Dog
class Dog : Animal
{
this(string n)
{
super(n); // 调用基类构造函数
}
override void speak() // 重写基类方法
{
writeln(name, ” barks!”);
}
}

// 结构体 (值类型)
struct Point
{
int x;
int y;
string toString() const // const方法,不修改结构体状态
{
return “(” ~ to!string(x) ~ “, ” ~ to!string(y) ~ “)”;
}
}

void main()
{
import std.stdio;
import std.conv; // 用于 to!string

Animal myAnimal = new Animal("Generic Animal");
myAnimal.speak(); // Generic Animal makes a sound.

Dog myDog = new Dog("Buddy");
myDog.speak(); // Buddy barks!

Animal anotherAnimal = new Dog("Max"); // 多态
anotherAnimal.speak(); // Max barks!

Point p = Point(10, 20); // 结构体实例化
writeln("Point p: ", p.toString());
Point q; // 默认构造
q.x = 5; q.y = 5;
writeln("Point q: ", q.toString());

}
“`

3. 接口

D语言支持接口定义,实现多态。

“`d
interface IShape
{
double area();
}

class Circle : IShape
{
double radius;
this(double r) { this.radius = r; }
override double area() { return 3.14159 * radius * radius; }
}

class Rectangle : IShape
{
double width, height;
this(double w, double h) { this.width = w; this.height = h; }
override double area() { return width * height; }
}

void main()
{
import std.stdio;
IShape[] shapes;
shapes ~= new Circle(5.0);
shapes ~= new Rectangle(4.0, 6.0);

foreach (shape; shapes) {
    writeln("Shape area: ", shape.area());
}

}
“`

4. 泛型编程(模板)

D语言的模板系统非常强大,支持函数模板、类模板、别名模板等。

“`d
// 函数模板
T max(T)(T a, T b)
{
return a > b ? a : b;
}

// 类模板
class Box(T)
{
T value;
this(T v) { this.value = v; }
void print() { writeln(“Box value: “, value); }
}

void main()
{
import std.stdio;
writeln(“Max int: “, max(10, 20)); // 实例化为 max!(int)
writeln(“Max double: “, max(3.14, 2.71)); // 实例化为 max!(double)
writeln(“Max string: “, max(“apple”, “banana”)); // 实例化为 max!(string)

auto intBox = new Box!int(123);
intBox.print();

auto stringBox = new Box!string("Hello D!");
stringBox.print();

}
“`

5. 元编程与CTFE

D语言的编译期函数执行(CTFE)允许在编译时执行D代码,这在模板元编程中非常有用,可以生成代码、进行复杂计算、验证类型等。

“`d
// 编译期斐波那契数列计算
long fibonacci(long n) pure @safe
{
if (n <= 1) return n;
return fibonacci(n – 1) + fibonacci(n – 2);
}

// 在编译期计算并赋值
enum FIB_10 = fibonacci(10); // 编译期执行 fibonacci(10)

void main()
{
import std.stdio;
writeln(“Fibonacci(10) at compile time: “, FIB_10); // 55
}
“`

6. 内存管理(GC与手动)

D语言默认提供垃圾回收(GC),但你也可以选择禁用GC或手动管理内存,这在性能敏感的场景非常有用。

  • GC分配: new 关键字分配对象通常由GC管理。
  • 手动分配: 使用 core.memory.GC.malloccore.memory.GC.free,或直接使用C的 malloc/free

第五部分:D语言标准库(Phobos)

D语言拥有一个强大且功能丰富的标准库Phobos,它提供了大量模块来处理各种任务:

  • std.stdio: 标准输入输出(writeln, readln 等)。
  • std.string: 字符串操作。
  • std.array: 数组操作、动态数组工具。
  • std.range: 范围(Range)是D语言中处理序列的强大抽象,支持惰性求值和链式操作,是函数式编程的关键。
  • std.algorithm: 各种算法(排序、过滤、映射等),与std.range结合使用非常高效。
  • std.datetime: 日期和时间处理。
  • std.json: JSON解析与生成。
  • std.path: 路径操作。
  • std.file: 文件系统操作。
  • std.concurrency: 并发编程原语(消息传递、共享内存)。

使用std.rangestd.algorithm的示例:

“`d
void main()
{
import std.stdio;
import std.range; // 导入范围模块
import std.algorithm; // 导入算法模块

// 生成一个从1到10的整数范围,过滤掉偶数,然后乘以2
auto result = iota(1, 11) // 生成1到10的序列
              .filter!(a => a % 2 != 0) // 过滤奇数
              .map!(a => a * 2)     // 每个元素乘以2
              .array();             // 将结果转换为动态数组

writeln("Filtered and mapped: ", result); // 输出 [2, 6, 10, 14, 18]

// 查找最大值
int[] numbers = [5, 2, 8, 1, 9, 4];
auto max_val = numbers.reduce!((a, b) => a > b ? a : b); // 或者 numbers.max
writeln("Max value: ", max_val); // 9

}
“`

第六部分:D语言的高级概念

1. @safe D与内存安全

D语言通过 @safe 关键字提供了一种可选的内存安全模式。在 @safe 函数中,编译器会强制执行一系列规则,防止常见的内存错误,如空指针解引用、越界访问等。这使得D语言在编写高可靠性代码时具有显著优势。

2. 契约式编程(Contracts)

D语言内置了对契约式编程的支持,通过 in (前置条件)、out (后置条件) 和 invariant (不变式) 关键字来增强代码的健壮性。

“`d
int divide(int numerator, int denominator)
in {
assert(denominator != 0, “Denominator cannot be zero”);
}
out (result) {
// 后置条件:结果 * denominator 应该约等于 numerator
// 这里只是一个简化示例,浮点数比较会更复杂
assert(numerator / denominator == result, “Incorrect division result”);
}
{
return numerator / denominator;
}

void main()
{
import std.stdio;
writeln(“10 / 2 = “, divide(10, 2));
// writeln(“10 / 0 = “, divide(10, 0)); // 会触发运行时断言错误
}
“`

3. 单元测试

D语言内置了单元测试支持,可以直接在模块文件中编写测试代码。

“`d
// mymodule.d
module mypackage.mymodule;

int add(int a, int b) {
return a + b;
}

unittest { // 单元测试块
import std.stdio;
assert(add(1, 2) == 3);
assert(add(-1, 1) == 0);
writeln(“Add function tests passed!”);
}
“`

运行 dub test 会编译并执行所有 unittest 块。

第七部分:学习资源与社区

  • D语言官网: dlang.org – 官方文档、教程、下载。
  • D Programming Language Tour: tour.dlang.org – 交互式D语言教程。
  • D语言论坛/邮件列表: 提问和获取帮助的最佳场所。
  • GitHub: 许多D语言项目和库都在GitHub上。
  • Learn D in Y minutes: learnxinyminutes.com/docs/d/ – 快速入门。

总结

D语言提供了一个独特而强大的组合:C++的性能和控制力,加上现代语言的便利性、类型安全特性和卓越的编译速度。从基础语法到高级特性,D语言都致力于让开发者能够编写出高效、可靠且易于维护的代码。

通过本指南,你应该对D语言有了初步的认识,并掌握了环境搭建和基本编程技巧。现在,是时候动手实践,编写你自己的D程序,探索Phobos标准库,并深入了解D语言的更多高级特性,如并发、协程和更复杂的元编程技巧。祝你在D语言的学习之旅中一帆风顺!


滚动至顶部