「ArchSummit·深圳」人工智能如何促进工业和制造领域的智能化转型? >>> 了解详情
写点什么

概览 CLI 之上的新语言——Boo

  • 2007-04-19
  • 本文字数:7001 字

    阅读完需:约 23 分钟

最近几年中,得益于 Java 和.NET 平台良好的可扩展性,在这两个平台上都出现了一大批令人激动的新语言。在 Java 领域内,人们欣喜地看到了 JRuby 和 Groovy 这两门语言的出现,它们均在语法、动作(Action)方面提供了很高程度的灵活性。若合理使用的话,会大大提高开发者的生产效率。.NET 平台上也确实出现了不少创造性的新语言,微软公司官方支持的 IronPython 和 F#都让人们对 CLI 的灵活性和可扩展性充满了信心。

在 IronPython 和 F#受到广泛关注和支持的同时,其他一些同样基于 CLI 的语言也在默默地争取着自己的生存空间。例如开源社区所推崇的 L#(一门 CLI 上运行的基于 Lisp 的语言)、IronRuby 和 Ruby.NET 等两个 Ruby 的实现等。

很多这类创新都是将现有的语言移植到 CLI 平台上(例如,IronPython 就是 CLI 上的 Python 语言,就像 JRuby 是 JVM 上的 Ruby 语言一样),但也出现了一些全新的、拥有自己独特语法的语言,虽然这些全新的语言也难免受到目前如日中天的各种流行语言的影响。boo 就是其中之一。boo 是 CLI 平台上的一种静态类型的语言,其很多特性都受到了 Python 的影响,但却又不是 Python 的简单移植。实际上,boo 并不在意代码的缩进,也不强迫我们使用 self 关键字。另外,boo 从根本上来讲还是一种静态类型语言,这也与 Python 的动态特性不尽相同。

借助于 boo 所内建的语言特性以及简单的语法结构,加上其静态特性,我们可以用该语言更加高效地编写.NET 应用程序,程序的执行效率甚至也能与 C#不相上下。另外,在 boo 中,我们还可以使用任何 CLI 平台上的现存类库,boo 代码同样能够容易地在其他 CLI 语言中被重用!

使用 boo 开发非常简单

Rodrigo B. de Oliveira 曾经对 C#的很多过于严格的编码规则(例如类型的强制转换)及其不能通过 shell 测试运行代码感到非常郁闷。于是 boo 语言应运而生,并很快发展成一个非常方便的.NET 和 Mono 通用的平台,基于该平台,我们能够创建 GUI 原型、单元测试甚至游戏等各类程序。

学习 boo 的最简单方法就是从 boo 的交互 shell 开始,boo 的交互 shell 又名 booish。在 booish 中,我们即可灵活地任意察看代码片断,进而理解 boo 的语法规则。

对于最常见的 hello world 程序来讲,boo 的视线非常简单——print 加上将要输出的字符串即可。

>>> print "Hello Scary World!"<br></br>Hello Scary World!需要说明的是,我们还可以将上述代码保存在代码文件中,然后使用booi命令执行该源文件。

C:\dev\projects\acme>booi src\helloworld.boo<br></br>Hello scary world!我们还可以用booc命令将helloworld.boo脚本编译成为 Windows 可执行文件,即将 boo 代码编译成合法的 CLI 应用程序。

C:\dev\projects\acmi>booc -out:bin/helloworld.exe src/helloworld.boo<br></br>Boo Compiler version 0.7.6.2237 (CLR v1.1.4322.2032)<br></br>C:\dev\projects\acme\bin>helloworld.exe<br></br>Hello scary world!boo 是一种静态类型的语言,每个变量都有自己的类型。例如,我们可以创建一个值为“Hello World”的 string 类型变量:

>>> var = "Hello world"<br></br>'Hello world'<br></br>>>> var.GetType()<br></br>System.String注意到这里并没有显式地将 var 声明为 string 类型,但由于 boo 的静态特性并根据该变量被设置的值,var 就自动地被设置成了 string 类型。

boo 字符串

与 Python 类似,boo 为字符串、集合等类型添加了很多灵活的内建(built-in)功能支持,让我们举例说明。

boo 支持字符串改写(使用 ${}语法),还支持 Python 风格的多行字符串。

>>> adj = "scary"<br></br>'scary'<br></br>>>> print "Hello ${adj} world"<br></br>Hello scary world多行字符串非常易于使用,更不用担心字符转义等问题。

firstname = "Joe"<br></br>lastname = "Dirt"<br></br>accountid = "A499"<br></br>amount = "1.32"<p> msg = """</p><br></br><person fname="${firstname}" lname="${lastname}"></person><br></br><account amount="${amount}" id="${accountid}"></account><p>"""</p>与 Python 和 Ruby 类似,正则表达式和集合类型(例如 list 和 map)的支持内建到了 boo 语言本身中,并提供了语法上的快捷使用方式。

正则表达式通过“/”定义,其实际的类型为System.Text.RegularExpressions.Regex。匹配则通过 Perl 风格的“=~”操作符完成。例如,如下代码即可用来匹配邮政编码信息:

>>> regx = /^\d{5}([-]\d{4})?$/<br></br>^\d{5}([-]\d{4})?$<br></br>>>> if '22101-4444' =~ regx:<br></br> print "yes"### boo 的集合类型

boo 支持三种内建的集合类型:普通数组(长度固定,且只能包含某一确定类型的数据)、列表(长度可变,能包含不同类型的数据)以及哈希表(用来存储名称 / 值对)。

数组

数组用来保存一系列相同类型的对象,不能超过某个预定的长度。在 boo 中的创建语法如下:

>>> myarray = (1,2,4,5)<br></br>(1, 2, 4, 5)我们也不能在数组中添加不同类型的数据。

>>> myarray.SetValue(6, 3)<br></br>>>> myarray<br></br>(1, 2, 4, 6)<br></br>>>> myarray.SetValue('test', 3)<br></br>System.InvalidCastException: Object cannot be stored in an array of this type.<br></br> at System.Array.InternalSetValue(Object value, Int32 index1, Int32 index2, Int32 index3)<br></br> at Input50Module.Main(String[] argv)### 列表

列表是一类长度不固定的、可被索引且能够包含多种不同类型的数组。这是一种非常灵活的类型,通过从 Python 中借来的方括号([])创建,属于Boo.Lang.List类型。

>>> mylist = [1, 2, 3, 4]<br></br>[1, 2, 3, 4]<br></br>>>> mylist.GetType()<br></br>Boo.Lang.List<br></br>>>> mylist.Add('test')<br></br>[1, 2, 3, 4, 'test']可以看到,boo 中的列表能够包含不同类型的对象,还能够使用 Add 方法添加新元素。若想了解列表目前包含了什么,我们可以使用 Contains 方法,甚至还能够通过询问逻辑问题实现:

>>> mylist.Contains(3)<br></br>true<br></br>>>> 'test' in mylist<br></br>true### 哈希表

boo 中的哈希表是一个保存名称 / 值对的容器。这些名称 / 值对均可为不同的类型。

>>> myhash = {".NET":"boo", "Java":"Groovy"}<br></br>{'Java': 'Groovy', '.NET': 'boo'}哈希表通过名称 / 值对实现,因此,若是输入了名称,那么将得到其值。在下面的代码中,我们输入了".NET",得到了’boo’。

>>> myhash[".NET"]<br></br>'boo'我们还可以使用 ContainsKey 或 ContainsValue 方法搜索哈希表。

>>> myhash.ContainsKey('Java')<br></br>true<br></br>>>> myhash.ContainsValue('Groovy')<br></br>true

迭代

与 Python 和 Ruby 类似,boo 也允许我们容易地对集合类型进行迭代。不过 boo 不支持 Ruby 或 Groovy 中常见的块(block)和闭包(closure)。

列表的迭代

通常情况下,boo 中的迭代是使用 for 语句实现的:

>>> mylist<br></br>[1, 2, 3, 4, 'test']<br></br>>>> for value in mylist:<br></br>... print value<br></br>...<br></br>1<br></br>2<br></br>3<br></br>4<br></br>test<br></br>>>> myint<br></br>9<br></br>>>> myarray<br></br>(1, 2, 4, 6)<br></br>>>> for i in myarray:<br></br>... print 2*i<br></br>...<br></br>2<br></br>4<br></br>8<br></br>12### 哈希表的迭代

我们也可以在哈希表上进行迭代:

>>> myhash<br></br>{'Java': 'Groovy', '.NET': 'boo'}<br></br>>>> for key in myhash:<br></br>... print key.Value<br></br>...<br></br>Groovy<br></br>boo需要注意的是,因为 boo 的哈希条目存贮在System.Collections.DictionaryEntry类型中,所以我们可以根据需要访问其 Key 和 Value 成员。

>>> for key in myhash:<br></br>... print key.Key<br></br>...<br></br>Java<br></br>.NET

boo 中的函数

boo 允许我们在类定义之外创建函数,这一点非常类似于 Python 和 Groovy。在 boo 中,函数是“一等公民”(即函数本身也是对象),使用def关键字创建。

例如,如下代码定义了一个值为’boo’的字符串。需要注意的是对于字符串类型,boo 中没有 Python 那样内建的 lower 方法。但创建一个 lower 方法却相当的简单:使用 def 关键字定义,并通过“as ”语句指定参数类型即可。

>>> str = "Boo"<br></br>'Boo'<br></br>>>> str.GetType()<br></br>>>> lower(str)<br></br>----^<br></br>ERROR: Unknown identifier: 'lower'.<br></br>>>> def lower(val as string):<br></br>... return val.ToLower()<br></br>...<br></br>>>> print lower(str)<br></br>boo

boo 中的 IO

通过使用 using 关键字,boo 让文件操作变得非常简单。我们根本不用担心文件处理中的一些常见问题,例如关闭文件等,因为 using 语句将自动为我们做好这些。

例如,读写某个本地文件将非常容易:

>>> import System.IO<br></br>>>> myfile = "SampleFile.txt"<br></br>'SampleFile.txt'<br></br>>>> using input = File.OpenText(myfile):<br></br>... for line in input:<br></br>... print line<br></br>...<br></br>Welcome to an easy<br></br>way to read files<br></br>using the most unscary language around:<br></br>BOO!通过使用函数,我们可以重新创建 Groovy 中 getText 风格的方法:

>>> import System.IO<br></br>>>> def GetText(file as string):<br></br>... retString = " "<br></br>... using input = File.OpenText(file):<br></br>... for line in input:<br></br>... retString += line<br></br>... return retString<br></br>...<br></br>>>> myfile = "SampleFile.txt"<br></br>'SampleFile.txt'<br></br>>>> assert GetText(myfile).Equals('Welcome to an easy way to read files using the most unscary language around: BOO! ')<br></br>>>>

与 NAnt 集成

通过 boo 任务,boo 能够与 NAnt 编译文件协同工作。下面这个例子就演示了 boo 与 NAnt 协同工作能够完成的任务——在某个 dll 上应用 FxCop,然后用 boo 将其中Critical Errors的个数统计出来:

<property name="fxcop.xml"></property><property name="fxcop.xml"></property> value="${build.dir}\bin\${build.config}\fxcop.xml"/><br></br><target depends="build" name="fxcop"></target><br></br><fxcop></fxcop><br></br><targets></targets><br></br><include name="${build.dir}\bin\${build.config}\${library}"></include><br></br><boo></boo><br></br> import System.IO<br></br> fpath = Project.Properties['fxcop.xml']<br></br> numerror = 0<br></br> using input = File.OpenText(fpath):<br></br> for line in input:<br></br> if line =~ /Level="CriticalError"/:<br></br> numerror++<p> print("There were ${numerror} Critical Errors")</p>

在 boo 中单元测试非常简单

因为 boo 能够与其他 CLI 库共同使用,所以 boo 代码也能够容易地使用 NUnit 的属性。

例如,如下代码使用了用来测试数据库的 NDbUnit,并用 NUnit 创建了一个简单的测试用例。在该测试用例中,我们使用 NDbUnit 的 API 插入一些数据,然后确认这些数据确实保存到了数据库中。

可以看到,与 C#相比,boo 代码显得简洁许多。因为 boo 并不使用分号和大括号,且类型声明也少了很多。

import NUnit.Framework<br></br>import NDbUnit.Core.OleDb<br></br>import NDbUnit.Core<br></br>import System.Data<br></br>import System<br></br>import System.Data.OleDb<p> [TestFixture]</p><br></br>class WordTest:<p> final CONN = "Provider=SQLOLEDB...."</p><br></br> final SCHEMA = "Dataset2.xsd"<br></br> final XML = "XMLFile2.xml"<br></br> fixture as OleDbUnitTest<p> [SetUp]</p><br></br> def configure():<br></br> fixture = OleDbUnitTest(CONN)<br></br> fixture.ReadXmlSchema(SCHEMA)<br></br> fixture.ReadXml(XML)<p> [Test]</p><br></br> def VerifyWordTableOle():<p> fixture.PerformDbOperation(DbOperationFlag.CleanInsert)</p><br></br> select = "select spelling from word where word.word_id = 2"<p> adapter = OleDbDataAdapter(select , CONN)</p><p> dta = DataSet()</p><br></br> adapter.Fill(dta, "word")<br></br> table = dta.Tables["word"]<p> for row as DataRow in table.Rows:</p><br></br> Assert.AreEqual("pugnacious", row[0],<br></br> "word spelling wasn't pugnacious")若你想以最快的速度开发单元测试,那么 boo 将是一个明智的选择。因为 Boo 支持属性(IronPython 并不支持),因此与 NUnit 配合起来也没有任何问题。

静态却不失动态特性

虽然我们并不需要显式声明变量的类型,但 boo 却的的确确是一种静态类型的语言。boo 在底层根据变量的值来自动决定变量的类型。例如,如下一段脚本创建了一个 string 类型,并尝试调用一个并不存在的方法。

var = "BOO"<br></br>var.lower()尝试编译该脚本,将得到如下错误:

C:\dev\projects\acme>booc -out:bin/statictypes.exe src/statictypes.boo<br></br>Boo Compiler version 0.7.6.2237 (CLR v1.1.4322.2032)<br></br>src/ statictypes.boo(3,5): BCE0019: 'lower' is not a member of 'string'.<br></br>1 error(s).若是直接运行该脚本,也将得到同样的错误:

C:\dev\projects\acme>booi src\statictypes.boo<br></br>src\statictypes.boo(3,5): BCE0019: Boo.Lang.Compiler.CompilerError: 'lower' is not a member of 'string'.尽管如此,boo 在类型方面仍提供了很多便利。通过使用duck类型,我们可以推迟编译期类型检查。若某个变量的类型为 duck,boo 将尝试用反射的方式调用方法。例如,若我们将 var 声明为duck类型,那么将不会得到编译期错误。而若是直接运行这段脚本,将得到一个不同的错误:

C:\dev\projects\acme>booi src\statictypes.boo<br></br>System.MissingMethodException: Method System.String.lower not found.<br></br> at System.RuntimeType.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Obje<br></br>ct[] args, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters)<br></br> at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] ar<br></br>gs)<br></br> at Boo.Lang.Runtime.RuntimeServices.Invoke(Object target, String name, Object[] args)<br></br> at StatictypesModule.Main(String[] argv)借助于 duck 类型,boo 能够以非常优雅的方式编写测试程序并控制 Internet Explorer:

>>> ie as duck =<br></br> System.Type.GetTypeFromProgID("InternetExplorer.Application")()<br></br>System.__ComObject<br></br>>>> ie.Visible = true<br></br>true<br></br>>>> ie.Navigate2("http://www.thediscoblog.com")<br></br>>>> links = ie.Document.getElementsByTagName("a")<br></br>System.__ComObject<br></br>>>> site = "http://thediscoblog.com/2007/02/04/currying-maximum-favor-with-groovy/"<br></br>'http://thediscoblog.com/2007/02/04/currying-maximum-favor-with-groovy/'<br></br>>>> for link in links:<br></br>... if(link.href.Equals(site)):<br></br>... link.click()<br></br>...<br></br>mshtml.HTMLAnchorElementClass注意到变量ie的类型为 duck,这样即可更加优雅地将执行消息传递给该实例,而并不会导致任何错误。

找到页面上的某个链接之后,我们可以点击该链接,然后精确验证随后页面中的内容。

>>> h3s = ie.Document.getElementsByTagName("h3")<br></br>System.__ComObject<br></br>>>> for h3 in h3s:<br></br>... if(h3.id.Equals("comments")):<br></br>... assert h3.innerText =~ "5 Responses"<br></br>...<br></br>mshtml.HTMLHeaderElementClass<br></br>>>> ie.Quit()

使用 boo 进行开发将显得非常自然

得益于其宽松的语法规则,boo 允许我们以更加轻松快捷的方式完成.NET 平台上的任务。若你正在设计程序的原型,或是创建用户界面元素,那么 boo 将是个绝佳的选择。不仅如此,使用 boo 创建的所有程序或组件均可以无缝地与其他.NET 类库配合使用,无论这些组件是用 C#、VB.NET 还是托管 C++ 编写的。boo 是一种.NET 平台上非常友好的语言,让我们能够不受约束地快速编写代码。还躲什么呢——今天就来试试 boo 吧!


译者简介:陈黎夫(Dflying Chen)是 InfoQ 中文站的志愿者翻译。他毕业于上海交通大学计算机科学专业,曾在微软公司 ASP.NET Ajax 创始团队——Windows Live Hotmail 担任软件开发工程师,使用 ASP.NET Ajax 早期版本参与开发了下一代 Email 系统 Windows Live Mail,以及 Windows Live Calendar 等产品。擅长 Web 相关技术。作为 ASP.NET Ajax 在中国的传道者之一,他在个人博客中写过大量相关技术文章,引起了广泛反响,已经成为国内访问量最大的ASP.NET Ajax 资源之一。著作/ 译作有《 ASP.NET Ajax 程序设计》、《 Atlas 基础教程》和《 CSS 禅意花园》等。加入 InfoQ 中文站志愿者翻译队伍,请邮件至 china-editorial@infoq.com

2007-04-19 01:243141
用户头像

发布了 37 篇内容, 共 81505 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

【面经分享,附答案】字节系统架构,一面,后端开发

小小怪下士

Java 程序员 面试

盘点那些日赚万金的爆款小游戏

FinFish

小游戏 小程序游戏 微信小游戏 爆款小游戏

Java程序员培训机构怎么选

小谷哥

RocketMQ Schema——让消息成为流动的结构化数据

Apache RocketMQ

RocketMQ

汽车之家基于 Milvus 的向量检索平台实践

Zilliz

数据库 向量检索 Milvus

阿里云视觉智能开放平台——人脸活体检测算法重磅升级

夏夜许游

服务升级 人脸活体检测 人脸人体

HTTP报文内容

穿过生命散发芬芳

HTTP 12月月更

新华三推出人工智能模型训练平台,让智慧算力触手可及

脑极体

Amazon 4.7 星评,领域新经典,了解服务设计就读它

图灵社区

产品经理 设计模式 服务设计

专利解析|数据中台—数据流配置弹框交互优化方法

元年技术洞察

数据中台 数字化转型 专利解析

Laravel中HasOne和BelongsTo的区别

ModStart

Clickhouse表引擎探究-ReplacingMergeTree

京东科技开发者

Clickhouse 数据分片 数据验证 存储数据 MergeTree

隐匿于喧嚣城市的世外桃源,「武汉浮生艺术馆」开放小程序预约通道,顺利举办多场艺术展览

天天预约

小程序 SaaS 预约工具 展览 艺术馆

这波无感升级有点秀——天翼云QEMU组件热升级方案来了

天翼云开发者社区

云计算 云主机 虚拟化

培训班出来前端程序员好找吗?

小谷哥

如何优化大场景实时渲染?HMS Core 3D Engine这么做

HMS Core

HMS Core

架构实战营 模块3-1

西山薄凉

「架构实战营」

迁移速度与计算性能兼得!天翼云DirtyLimit技术大显身手

天翼云开发者社区

虚拟机 迁移 弹性计算

软件测试培训 | 在霍格沃兹测试开发学社学习是种怎样的体验?

霍格沃兹测试开发学社

重磅!TDengine 3.2.0 正式发布

TDengine

数据库 tdengine 时序数据库

小游戏流量变现都有哪些窍门?

FinFish

小游戏 微信小程序-游戏 小程序游戏 微信小游戏

如何优化大场景实时渲染?HMS Core 3D Engine这么做

最新动态

参加大数据培训可以找到工作吗

小谷哥

企业转型难?火山引擎数智平台提供数智升级新路径

字节跳动数据平台

大数据 数据中台 12 月 PK 榜

智能合约DAPP开发WEB3.0系统搭建技术

薇電13242772558

智能合约

HMS Core 3D流体仿真技术,打造移动端PC级流体动效

最新动态

在北京选择哪家大数据培训机构

小谷哥

学习掌握哪些前端技术才能找到好工作?

小谷哥

【经验总结】HDI与普通PCB的4点主要区别

华秋PCB

工艺 PCB PCB设计

数据存储,消息队列的高可用保障

C++后台开发

数据库 数据结构 消息队列 后端开发 linux开发

大咖说·开源人说|数据库 PolarDB 开源的商业逻辑与价值思考

大咖说

数据库 阿里云 开源

概览CLI之上的新语言——Boo_.NET_Andy Glover_InfoQ精选文章