强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

03 第一个程序

第 03 章:第一个程序

3.1 最简单的 Nim 程序

创建文件 hello.nim

# hello.nim
echo "Hello, World!"

编译并运行:

nim c -r hello.nim

输出:

Hello, World!

这就是 Nim 的全部——一行代码,一个完整的程序。没有 main 函数,没有类,没有命名空间声明。

编译过程详解

nim c hello.nim          # 仅编译,生成 hello(Linux)或 hello.exe(Windows)
nim c -r hello.nim       # 编译并运行
nim c -o:myapp hello.nim # 指定输出文件名

编译步骤:

hello.nim → [Nim 编译器] → hello.c → [GCC/Clang] → hello(可执行文件)

3.2 基本输出

echo 函数

echo 是 Nim 中最常用的输出函数:

# 输出字符串
echo "Hello, Nim!"

# 输出数字
echo 42
echo 3.14

# 输出多个值(用逗号分隔)
echo "Name: ", "Nim", ", Version: ", NimVersion

# 输出表达式
echo "2 + 3 = ", 2 + 3

# 输出序列
echo @[1, 2, 3, 4, 5]

格式化输出

# 方法一:字符串拼接
let name = "Nim"
let version = 2
echo "Welcome to " & name & " " & $version & "!"

# 方法二:使用 & 格式化字符串(需要 import std/strformat)
import std/strformat

let pi = 3.14159
echo &"Pi is approximately {pi:.2f}"
# 输出: Pi is approximately 3.14

let items = 5
let price = 9.99
echo &"Total: {items} × ${price:.2f} = ${items.float * price:.2f}"
# 输出: Total: 5 × $9.99 = $49.95

write 和 writeLine

# write 不换行,echo 换行
stdout.write "Hello, "
stdout.write "World!"
stdout.write "\n"

# writeLine 等同于 echo
stdout.writeLine "This is a line"

3.3 基本输入

# 读取一行输入
echo "What is your name?"
let name = stdin.readLine()
echo "Hello, ", name, "!"

# 读取整数
echo "Enter a number:"
let num = parseInt(stdin.readLine())
echo "You entered: ", num

# 读取多个值
echo "Enter two numbers (space separated):"
let parts = stdin.readLine().split(" ")
let a = parseInt(parts[0])
let b = parseInt(parts[1])
echo &"{a} + {b} = {a + b}"

3.4 NimScript

Nim 支持 .nims 脚本文件,无需编译即可运行:

# 直接运行脚本
nim e hello.nims

# 或者给脚本添加执行权限
chmod +x hello.nims
./hello.nims

hello.nims

#!/usr/bin/env nim e
echo "Running as NimScript!"
echo "Nim version: ", NimVersion
echo "Current OS: ", hostOS

NimScript 与编译模式的区别:

特性编译模式 (nim c)脚本模式 (nim e)
运行速度极快(原生代码)较慢(解释执行)
系统调用完整支持有限制
FFI完整支持不支持
importc完整支持不支持
适用场景应用开发构建脚本、配置

3.5 项目结构

3.5.1 标准项目布局

myproject/
├── src/                    # 源代码目录
│   ├── myproject.nim       # 入口文件
│   ├── myproject/          # 模块目录
│   │   ├── utils.nim
│   │   ├── models.nim
│   │   └── config.nim
│   └── myprojectpkg/       # 包模块目录
│       └── private.nim
├── tests/                  # 测试目录
│   ├── test_utils.nim
│   └── test_models.nim
├── docs/                   # 文档目录
├── bin/                    # 编译输出目录
├── nimcache/               # 编译缓存(不应提交到版本控制)
├── config.nims             # 项目配置
├── myproject.nimble        # 包配置
├── .gitignore
└── README.md

3.5.2 nimble init 生成的项目

nimble init myproject

这会创建:

myproject/
├── src/
│   └── myproject.nim       # 入口
├── tests/
│   └── test1.nim           # 测试
└── myproject.nimble         # 包描述

默认入口文件 src/myproject.nim

# This is just an example to get you started. A typical library package
# exports the main API in this file. Note that you cannot rename this file
# but you can remove it if you wish.

proc add*(x, y: int): int =
  ## Adds two numbers together.
  return x + y

when isMainModule:
  echo add(2, 3)

3.5.3 命名约定

组件约定示例
源文件小写下划线my_module.nim
模块目录小写下划线my_module/
包名小写myproject
入口文件与项目同名myproject.nim
测试文件test_ 前缀test_utils.nim

3.6 编译模式详解

3.6.1 Debug 模式(默认)

nim c main.nim
# 等同于
nim c --assertions:on --checks:on --hints:on main.nim

特点:

  • 启用所有运行时检查
  • 包含调试信息
  • 未启用优化
  • 适合开发调试

3.6.2 Release 模式

nim c -d:release main.nim

特点:

  • 启用编译器优化
  • 关闭运行时检查
  • 生成更小的二进制文件
  • 适合生产部署

3.6.3 Danger 模式

nim c -d:danger main.nim

特点:

  • 关闭所有安全检查
  • 最大优化
  • 可能导致未定义行为
  • 仅用于性能基准测试

3.6.4 对比表

特性DebugReleaseDanger
运行时检查
数组边界检查
优化级别O0O3O3
调试信息
二进制大小
运行速度最快
适用场景开发调试生产部署性能测试

3.7 条件编译

when 语句

# 根据操作系统选择不同行为
when defined(windows):
  echo "Running on Windows"
elif defined(linux):
  echo "Running on Linux"
elif defined(macosx):
  echo "Running on macOS"
else:
  echo "Unknown OS"

# 根据编译模式
when defined(release):
  echo "Release build"
else:
  echo "Debug build"

# 根据编译后端
when defined(js):
  proc alert(msg: string) {.importjs: "alert(#)".}
  alert("In JavaScript!")
else:
  echo "In native code!"

自定义编译标志

# 使用 -d 标志定义自定义符号
# 编译: nim c -d:verbose -d:version=2 main.nim

when defined(verbose):
  echo "Verbose mode enabled"

const Version {.intdefine.} = 1
echo "Version: ", Version

定义常量

# 在命令行定义
# nim c -d:appName=MyApp main.nim

const appName {.strdefine.} = "DefaultApp"
echo "Running: ", appName

3.8 多文件项目示例

创建项目

mkdir -p myapp/src/myapp
cd myapp
nimble init myapp -y

src/myapp.nim(入口)

# src/myapp.nim
import myapp/[calculator, formatter]

when isMainModule:
  let result = add(10, 20)
  echo formatResult("Addition", 10, 20, result)
  
  let product = multiply(5, 6)
  echo formatResult("Multiplication", 5, 6, product)

src/myapp/calculator.nim

# src/myapp/calculator.nim

proc add*(a, b: int): int =
  ## Add two integers
  return a + b

proc subtract*(a, b: int): int =
  ## Subtract b from a
  return a - b

proc multiply*(a, b: int): int =
  ## Multiply two integers
  return a * b

proc divide*(a, b: float): float =
  ## Divide a by b
  if b == 0:
    raise newException(DivByZeroDefect, "Cannot divide by zero")
  return a / b

src/myapp/formatter.nim

# src/myapp/formatter.nim
import std/strformat

proc formatResult*(op: string, a, b, result: int): string =
  ## Format a calculation result as a string
  &"{op}: {a} and {b} = {result}"

proc formatCurrency*(amount: float, currency: string = "$"): string =
  ## Format a number as currency
  &"{currency}{amount:.2f}"

编译运行

nim c -r src/myapp.nim

输出:

Addition: 10 and 20 = 30
Multiplication: 5 and 6 = 30

3.9 注释与文档

# 这是单行注释

#[这是
多行
注释]#

proc add*(a, b: int): int =
  ## 计算两个整数的和
  ## 
  ## .. code-block:: nim
  ##   echo add(1, 2)  # 输出 3
  return a + b

type
  User* = object
    ## 用户对象
    ## 
    ## 存储用户的基本信息
    name*: string  ## 用户名
    age*: int      ## 年龄

生成文档:

nim doc src/myapp.nim
# 生成 src/myapp.html

3.10 实用开发技巧

快速测试代码片段

# 使用 -e 标志直接执行代码
nim e -e "echo 2 + 2"

# 使用 --eval 标志
nim --eval:"echo \"Hello\""

查看编译器输出的 C 代码

# 查看生成的 C 代码
nim c --genScript main.nim
cat nimcache/main.c

交叉编译

# 为 Linux ARM64 编译
nim c --os:linux --cpu:arm64 main.nim

# 为 Windows 编译
nim c --os:windows --cpu:amd64 main.nim

本章小结

要点内容
编译命令nim c -r file.nim
输出函数echostdout.write
输入函数stdin.readLine()
格式化strformat 模块的 &"{}" 语法
脚本模式nim e file.nims
项目结构src/(源码)、tests/(测试)、bin/(输出)
编译模式Debug(默认)、Release(-d:release)、Danger(-d:danger

练习

  1. 编写一个程序,读取用户输入的姓名和年龄,格式化输出问候语
  2. 创建一个多文件项目,包含一个工具模块和一个主入口
  3. 分别使用 Debug 和 Release 模式编译,比较二进制文件大小
  4. 编写一个 NimScript 文件,列出当前目录的所有 .nim 文件

扩展阅读


上一章:安装与环境配置 | 下一章:变量与类型