如何在不输入名称两次的情况下打印变量名称及其值?

时间:2010-09-04 00:08:08

标签: macros metaprogramming d

调试时,执行此操作非常有用:

var = calc()
print("var:", var)

有没有哪种语言容易做到?在C和C ++中,您可以使用stringify宏运算符#,在Ruby中我发现了这个问题:

Ruby - print the variable name and then its value

使用符号的解决方案:var和block就是我想要的。

在D中,我使用了这个:

void trace(alias msg)() {
    writeln(msg.stringof ~ ":" ~ to!string(msg));
}

但我不确定这是最好的方法,因为它只适用于简单的情况。我尝试了几种方法,但有时你可以得到字符串,但不是值(因为变量超出范围),或者你必须首先混合模板然后调用函数。

那么其他语言呢?蟒蛇? F#?嘘? Shell脚本(无论哪个shell)? Perl的? (我更喜欢远离Perl,tho)。 TCL? Lisp,Scheme? Java的? (Java不太可能这样做)。

即使在我找到某种解决方案的语言中,它也适用于简单的情况。如果我想打印任意表达式怎么办?

如果我正在设计一种语言,这个功能将是必备的。 : - )

3 个答案:

答案 0 :(得分:5)

这是在D中执行它的一种非常通用但稍微丑陋的方式,使用编译时函数评估(CTFE)生成代码作为字符串文字,并使用mixin语句来评估它:

import std.stdio, std.math;

// CTFE function that generates trace code.
string trace(string varName) {
    return "writeln(\"" ~ varName ~ ":  \", " ~ varName ~ ");";
}

void main() {
    // Trace a function call.
    mixin(trace("sqrt(5)"));

    // Trace a variable.
    int foo = 5;
    mixin(trace("foo"));
}

唯一的问题是在任何地方手动输入mixin都是冗长的,无论你想跟踪什么都需要在一个丑陋的字符串文字中。

请注意,D中有两种mixins。模板mixin在很多方面都表现得更好,但字符串mixins(在本例中使用)大致与它一样, any 代码原则上可以通过CTFE生成,然后混合进来。

答案 1 :(得分:2)

任何Lisp都是微不足道的。在Racket(néePLT计划)中:

(define-syntax-rule (debug-info expr)
  (format "~a is ~a" (quote expr) expr))

(let ((long-boring-name 5))
   (display (debug-info long-boring-name)))

# displays "long-boring-name is 5"

(let ((fifty-two 52))
  (display (debug-info (+ fifty-two 6))))

# displays "(+ fifty-two 6) is 58"

答案 2 :(得分:0)

我认为Tcl基本上是“没有任何数据结构的Lisp”(用字符串代替......好吧,几乎任何东西,真的),所以它在Tcl和Lisp一样容易。

已经过了几年,但我觉得这样的事情可以解决问题:

proc log_var {var} {
    upvar 1 $var x
    puts "$var is: $x"
}

set my_var 5
log_var my_var

我认为可能有一种方法可以使用uplevel来扩展它以适用于任意表达式。