收藏 分销(赏)

五分钟学Tcl(还可以).doc

上传人:仙人****88 文档编号:9149622 上传时间:2025-03-15 格式:DOC 页数:9 大小:44.50KB
下载 相关 举报
五分钟学Tcl(还可以).doc_第1页
第1页 / 共9页
五分钟学Tcl(还可以).doc_第2页
第2页 / 共9页
点击查看更多>>
资源描述
五分钟学Tcl Concept 1: 程序是由命令(command)组成的 Tcl语言最基本的概念是:命令。程序是由一条接一条的命令构成的。举例来说,设置变量’a’为5,并且打印它的值,你写两条命令: set a 5 puts $a 命令是以空格分隔的单词组成的。一条命令以换行符或分号(‘;’)结尾。在Tcl中,万事皆命令 – 正如你看到的那样,Tcl中并没有赋值符。要给一个变量赋值,需要用set命令,它将第一个参数所指定的变量,赋值为第二个参数所指定的值。 几乎所有的Tcl命令都会返回一个值,比如set命令返回的值就是其所赋的值。如果set命令仅指定一个参数(变量名),那么其返回值就是该变量的当前值 Concept 2: 命令替换(Command subsitution) 其次的概念是:命令替换。在一个命令中,某些参数可能出现在[ ]中。这种情况下,参数被替换成[ ]中代码的返回值。例如: set a 5 puts [set a] 第二条命令的第一个参数,[set a],会被替换成“set a”的返回值(即 5)。在替换之后,这条命令就从 puts [set a] 转换成 puts 5 然后,它被正常执行。 Concept 3: 变量替换(Variable subsitution) 如上例,总是用set命令来引用变量值显得太冗长了些,因此Tcl早期版本就已经引入了新的变量替换的概念。如果一个变量名前面加上 $ 字符,那么它被替换成该变量的值。所以,就没有必要用 puts [set a] 而可以使用 puts $a Concept 4: 组(Grouping) 如果命令由空格分隔的单词构成,那么如何处理包含空格的参数呢?比如: puts Hello World 是一条不正确的语句,因为Hello和World是两个独立参数。解决方式是分组(grouping)。包含在""中的文本被认为是单个参数,所以正确的语句是: puts "Hello World" 命令替换和变量替换在这种分组中也是有效的,比如我可以写: set a 5 set b foobar puts "Hello $a World [string length $b]" 结果是"Hello 5 World 6". 另外,转义字符如\t, \n 仍然有效.还有另一种Grouping方式,这种方式下所有的特殊字符都只有其字面含义,而不会发生变量替换。{和}之间的所有字符被认为是一个整体的参数,其中不会发生任何提环操作。所以: set a 5 puts {Hello $a World} 会打印出 Hello $a World. 仍然是Concept 1: 万事皆命令 前面介绍了概念1:程序是由命令所组成的。事实上其含义可能超出你所想象。比如如下代码: set a 5 if $a { puts Hello! } if是一个命令,它带有2个参数。第一个参数是变量a的值,第二个参数是字串{ … puts Hello! … }。 if命令使用了Eval命令的一个特殊版本来执行参数2中的脚本(稍后会有Eval介绍),并且返回其结果。当然,你可以编写你自己的if命令,或者其他的控制结构。你甚至可以重定义if本身,并且给它增加一些功能! Concept 5: 一切皆字串,没有类型(Everything is a string - no types) 下面的代码能够按照你想象的方式正确运行: set a pu set b ts $a$b "Hello World" 是的,在Tcl语言中一切都发生在运行时,并且是动态的:它是一种“迟绑定” (late binding)语言,并且没有数据类型。命令名并不是特殊类型,仅仅是字符串而已。数值也只是字符串,Tcl代码也是(还记得我们给if命令传递的字符串,做为它的第二个参数吗?)。在Tcl中,一个字符串代表什么,取决于那条处理它的命令。 同样的“5”,在“string length 5”命令中,会被看成一个字符串;而在“if $a …”命令中,则被看作一个布尔值。当然,命令会检查值的格式是否正确,如果我试图在“bar”上增加一个“foo”值,Tcl会产生一条异常,因为它不能把“bar”和“foo”解析成数字值。Tcl会很严格地执行这类检查,你不会像PHP中遇到那些愚蠢的自动类型转换。类型转换仅发生在该字符串能够有意义地转换成命令所需要的参数时。 所以,Tcl是非常动态的,但想象一下,它甚至和当前的Ruby实现差不多快。在Tcl的实现中,有一个小把戏:对象(不是OOP概念,仅指表示Tcl值的C Struct)缓存了给定的字符串上一次被使用时的原生值。如果一个Tcl值总是被用作一个数字,那么对应的C struct就会包含一个整数值,只要下一条命令仍然把它用作整数值,那么它的字符串表示就根本不会被触及(直接使用缓存的整数值)。实际实现比这复杂一点,但结果就是程序员不必去考虑类型,而且程序仍然运行得和其他拥有显示类型的动态语言一样快。 Concept 6: Tcl列表(Tcl lists) Tcl中更有趣的类型之一是列表(list)。列表通常是一个Tcl程序的核心结构:一个Tcl列表就是一个合法的Tcl命令(并且二者最终都是字符串)!就最简单的格式来说,列表和命令相似:以空格分隔的单词。比如字符串“a b foo bar”是一个有4个元素的列表。有一些命令用来执行诸如获取列表特定范围的元素,增加元素等等。当然列表中的元素可以包含空格,所以,为了创建正确格式的列表,可以用list命令。例如: set l [list a b foo "hello world"] puts [llength $l] llength返回列表的长度,所以上述程序会打印出4。lindex会返回指定位置的元素,所以“lindex $l 2”会返回“foo”,等等。和Lisp语言类似,在Tcl中程序员可以利用list模拟很多概念。 Concept 7: Tcl中的数学运算(Math in Tcl) 我猜很多资深Lisp程序员已经注意到Tcl是一种“前标注”(prefix-notation)语言,所以你可能猜测如同Lisp中一样,Tcl中的数学运算也是使用数学运算符作为命令,比如:puts [+ 1 2]。事实上,Tcl以另一种方式运作:为了使Tcl更友好,有一个命令可以以常见的数学运算表达式作为参数值并对它求值,这就是expr命令,Tcl中的数学运算就象这样: set a 10 set b 20 puts [expr $a+$b] 象if和while这样的命令,在其内部使用了expr命令,用来对表达式求值,比如: while {$a < $b} { puts Hello } 这里,while命令有两个参数 -- 第一个参数在每一次循环时被求值,并检查是否为true,第二个参数则在每次循环中对自身求值(eval)。我认为数学运算命令不是没有设计为内建命令可能是一个设计错误,expr命令可能在执行复杂运算时很有效,但对于一些简单运算比如计算两个数字之和,[+ $a $b]更方便。 Concept 8: 过程(Procedures) 自然,Tcl程序员也可以写一个过程(即用户自定义命令),从而使用数学运算符作为命令,就象这样: proc + {a b} { expr {$a+$b} } proc命令用来产生一个过程:第一个参数是过程名,第二个参数是一个列表,作为这个过程的输入参数,最后一个参数是这个过程的程序体。注意第二个参数,是一个Tcl列表。正如你所看到的,过程的最后一条命令的返回值就是这个过程的返回值(除非你显式地用了return命令)。等一下…Tcl中万事皆命令不是吗?所以我们可以用一种简单的方式为+, -, *, …定义过程,而不是分别写4个过程: set operators [list + - * /] foreach o $operators { proc $o {a b} [list expr "\$a $o \$b"] } 现在我们可以使用[+ 1 2], [/ 10 2]等等。当然这种方式更好。在Tcl中,过程名可以和内建命令相同,所以你可以重定义Tcl本身。比如,为了写一个Tcl宏系统,我重定义了proc命令。重定义过程对写profiler也很有用。重定义一个内建的命令后,你仍然可以调用它,前提是你在用proc命令改写它之前,用rename命令为它重命名。 Concept 9: Eval and Uplevel 如果你正在读这篇文章,你应该已经知道Eval命令。命令eval {puts hello}当然会对(作为参数)传递给它的代码进行求值,如同其他编程语言一样。在Tcl中,有另一个“野兽”,uplevel命令,它能够在调用者的上下文(context)中对代码进行求值,或者不管是否有意义,在调用者的调用者(或直接在最高层)进行求值。这就是说,Lisp中的macro,在Tcl中简单的过程就可以实现。例如:在Tcl中,没有内建的repeat命令可以象这样使用: repeat 5 { puts "Hello five times" } 但是使它生效很简单。 proc repeat {n body} { set res "" while {$n} { incr n -1 set res [uplevel $body] } return $res } 注意我们保存了最后一次求值的结果,所以我们的repeat命令(象其他Tcl命令一样)返回最后一个求值结果。一个例子: set a 10 repeat 5 {incr a} ;# Repeat will return 15 正如你猜测的那样,incr命令用来把一个整数增加1(如果你省略第2个参数的话)。“incr a”在调用者上下文中(也就是前一个堆栈帧)被执行 祝贺你,你已经了解了超过90%的Tcl概念! 为什么Tcl很强大? 我不想向你展示Tcl的每一个特性,但我有一个观念:很多编程任务可以用Tcl以一种优雅的方式来解决。需要强调的是,我认为Tcl确实有很多缺陷,但其中的大多数并不是由编程语言本身引起的。我认为Tcl派生语言(Tcl语言能够根据应用领域的不同进行自身的定制)有潜力能够和流行的Ruby,Lisp以及Python在各种领域进行竞争,如Web编程,网络编程,GUI开发,DSL以及脚本语言。 简单的语法,可伸缩性 Tcl语法非常简单,你可以用数行代码就可以写出一个解析器。我提到过我曾经写过一个Tcl宏系统,它可以做复杂的代码级转换。同时,Tcl语法时可伸缩的,你可以让它看上去像algol语言,这取决于你的编程风格。 没有类型,但是有严格的格式检查 Tcl中没有类型概念,你也不必去做类型转换,但是,你不会轻易地引入错误,因为字符串的格式检查是非常严格的。甚至,你不必要去做序列化。你需要在TCP Socket上传递一个复杂的Tcl列表吗?你只需要写:puts $socket $mylist.在Socket的另一侧读出这个列表,你只需要写:set mylist [read $socket]。这就完成了。 强大的,事件驱动的I/O模型 Tcl的I/O库有内建的事件驱动型编程模型。不需要特殊扩展,你就可以写出很复杂的网络通信程序,这很有趣。一个例子:下面的程序是一个并发的(内部使用了select(2))TCP Server,它向每一个客户端输出当前的时间。 socket -server handler 9999 proc handler {fd clientaddr clientport} { set t [clock format [clock seconds]] puts $fd "Hello $clientaddr:$clientport, current date is $t" close $fd } vwait forever Tcl很好地处理了无阻塞的I/O操作和事件,即使Socket的输出Buffer已满,你甚至可以向它输出内容。Tcl会自动为你缓存,等待Socket有足够的输出Buffer时,Tcl在后台发送缓存数据 Python用户看到这里会有些面熟:Python的“Twisted”框架允许你做同样的事,但Tcl语言内建同样的功能已有数年。 多范式(Multiple paradigms) 在Tcl中,你可以混合地编写面向对象的代码,面向过程的代码,或紧急代码,这有点象Common Lisp语言。在过去,已经有了很多OOP系统和面向过程的系统。有很多类似SmallTalk的OOP系统,很多就是用Tcl自身实现的。此外,Tcl允许你编写原语(意即Tcl允许对语言自身进行扩充)。一个例子是lmap lmap i {1 2 3 4 5} { expr $i*$i } 这段代码将返回平方值的列表,1 4 9 16 25。(在Lisp语言中)你可以在lamba(也是由Tcl自身实现的)的基础上编写一个类map的过程,但Tcl语言已经以一种更自然的方式提供了你想要得。注意一下,在其他语言中,你想要在编程语言中增加一个原语是多么严苛的事。 核心数据结构: 列表 If you are a Lisp programmer you know how beautiful is to have a flexible data structure like the list everywhere in your programs, especially when the literal is as simple as "foo bar 3 4 5 6" in most cases. 可编程的编程语言(通过uplevel) 通过 eval, uplevel, upvar以及tcl其他强大的introspection能力,你可以重新定义Tcl语言,并且发明一些新的解决问题的方法。例如,如果在一个过程的首句调用下面的有趣命令,它将会魔法般地记录这个过程的一个备忘版本: proc memoize {} { set cmd [info level -1] if {[info level] > 2 && [lindex [info level -2] 0] eq "memoize"} return if {![info exists ::Memo($cmd)]} {set ::Memo($cmd) [eval $cmd]} return -code return $::Memo($cmd) } 然后,当你写一个过程时,只需写类似下面的语句: proc myMemoizingProcedure { ... } { memoize ... the rest of the code ... } i18n支持 Tcl is probably the language with the best internationalization support. Every string is internally encoded in utf-8, all the string operations are Unicode-safe, including the regular expression engine. Basically, in Tcl programs, encodings are not a problem - they just work. Tcl可能是对国际化支持最好的语言。每一个字符串在其内部都以utf-8编码,所有的字符串操作都是Unicode-safe,包括正则表达式引擎。基本上,在Tcl中,编码不是一个问题 – 它们已经在工作。 Radical language modifications = DSL If you define a procedure called unknown it is called with a Tcl list representing arguments of every command Tcl tried to execute, but failed because the command name was not defined. You can do what you like with it, and return a value, or raise an error. If you just return a value, the command will appear to work even if unknown to Tcl, and the return value returned by unknown will be used as return value of the not defined command. Add this to uplevel and upvar, and the language itself that's almost syntax free, and what you get is an impressive environment for Domain Specific Languages development. Tcl has almost no syntax, like Lisp and FORTH, but there are different ways to have no syntax. Tcl looks like a configuration file by default: disable ssl validUsers jim barbara carmelo hostname foobar { allow from 2:00 to 8:00 } The above is a valid Tcl program, once you define the commands used, disable, validUsers and hostname. Much more Unfortunately there isn't room to show a lot of interesting features: most Tcl commands just do one single thing well with easy to remember names. Strings operations, introspection and other features are implemented as single commands with subcommands, for example string length, string range and so on. Every part of the language that gets indexes as argument support an end-num notation, so for example to take all the elements of a list but not the first nor the last you just write: lrange $mylist 1 end-1 And in general there is a lot of good design and optimization for the common case inside. Moreover the Tcl source code is one of the best written C programs you'll find, and the quality of the interpreter is amazing: commercial grade in the best sense of the word. Another interesting thing about the implementation is that it works exactly the same in different environments, from Windows to Unix, to Mac OS X. No quality difference among different operating systems (yes, including Tk, the main GUI library of Tcl).
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服