打开网易新闻 查看精彩图片

1979年Unix Shell诞生了一个偷懒技巧,程序员终于不用在代码里一行行拼接字符串。45年后,这个叫"heredoc"的功能成了Perl的隐藏彩蛋,连PHP和Ruby都跟着抄了作业。

写过多行文本的程序员都懂那种痛:邮件模板、SQL语句、HTML片段,每行末尾加个换行符\n,再用点号连起来,代码长得像个楼梯。Perl的heredoc(此处文档)直接把整块文本塞进代码,像往信封里塞信纸一样自然。

来看个真实对比。传统写法:

my $email_template = "Dear %s,\n" . "\n" . "You just won %d at our lottery!\n" . "To claim your prize, just click on the link below.\n";

heredoc写法:

my $email_template = <<~_END_OF_MAIL_; Dear %s, You just won %d at our lottery! To claim your prize, just click on the link below. _END_OF_MAIL_

第二版少了4个引号和3个连接符,眼睛不用在行间跳来跳去。维护时改文本内容,也不用数哪个\n漏了。

打开网易新闻 查看精彩图片

~符号是Perl 5.26才加的"智能缩进"

~符号是Perl 5.26才加的"智能缩进"

heredoc的核心符号是<<,后面跟自定义结束标记。Perl 5.26(2017年发布)加了带波浪号的变体<<~,能自动吃掉每行左边的空格。

这个设计解决了一个真实痛点:代码缩进和文本内容打架。没~的时候,要么heredoc内容顶格写破坏代码结构,要么保留缩进导致输出带一堆前导空格。~符号让解释器以结束标记的缩进为基准,统一剃掉左边多余空白。

结束标记完全自定义,习惯上用大写加下划线(如_END_MAIL_),但技术上可以是任意字符串。用双引号或不用引号时,heredoc内部支持变量插值;单引号则原样输出,和Perl的普通字符串规则一致。

PHP和Ruby的"致敬"各有取舍

PHP和Ruby的"致敬"各有取舍

Perl从Shell借来heredoc,PHP和Ruby又从Perl借走,但三家实现细节并不相同。

PHP的heredoc语法接近Perl,用<<

打开网易新闻 查看精彩图片

Ruby的heredoc更灵活,支持<<-MARKED语法允许结束标记缩进,但缩进处理逻辑和Perl的<<~不同。Ruby 2.3还加了<<~符号,行为才和Perl的<<~接近。

三家的变量插值规则也略有差异,迁移代码时容易踩坑。

为什么现代语言还在用这个"老古董"

为什么现代语言还在用这个"老古董"

模板引擎、ORM、DSL……现代编程里多行文本的场景一点没少。heredoc没被取代,因为它解决的是"代码里的文本"问题,而非"文本生成"问题。

当你需要在源码里硬编码一段SQL、一段错误提示、一段测试数据,heredoc比外部文件省一次IO,比字符串拼接省一堆符号。它不是革命性创新,是程序员和眼睛疲劳之间的和解方案。

Perl 5.26的~符号升级说明这门语言还在迭代。2024年Perl 5.40发布时,heredoc的行为又微调了几处边界情况——一个45岁的语法特性,至今有人维护。

你最后一次在代码里手写heredoc是什么时候?是懒得拆成外部文件,还是真有必须内嵌的理由?