Vala

Vala是一門面向对象的编程语言，由自舉編譯器產生C语言代碼和使用GObject系統，允许在GNOME运行时库的基础上使用大量现代的编程技巧。通过使用GLib和GObject，Vala提供了动态类型系统和基于引用计数（reference counting）系统的記憶體管理的功能。 Vala是一门编程语言，结合了脚本语言的高级编程语言建造时间性能，与低级的编程语言运行时间性能。相较于用C写成的应用和库，它致力于将现代编程语言特征带给GNOME开发者，而不用强加任何额外的运行时间要求，并且不用使用不同的ABI。Vala的语法类似于C#，并为了更好的适应GObject类型系统而做了修改。 Vala由Jürg Billeter构想，并由他和Raffaele Sandrini实现，他希望开发GNOME应用能有对C语言的更高级替代者。他们的确喜欢C#的语法和语义，但不想使用Mono，故而他们在2006年5月完成了一个编译器。最初它使用C来引导（英语：Bootstrapping (compilers)），一年后（在2007年7月的版本0.1.0发行中），Vala编译器实现了自舉。 Vala使用GLib和它的子模块（GObject、GModule、GThread、GIO）作为核心库，它们支持多数操作系统，并提供：平台无关线程、输入/输出、文件管理、网络套接字、插件、正则表达式等。Vala的语法目前支持如下现代语言特征： 接口 属性 信号（英语：Signal programming） Foreach lambda表达式 局部变量的类型推论 泛型 非空类型（英语：Void safety） 辅助内存管理 异常处理 图形用户界面可以使用GTK部件工具箱和Glade GUI建造器（英语：Graphical user interface builder）来开发。 对于内存管理，GType或GObject系统提供引用计数。在C语言中，编程者必须手工管理增加和移除引用，而在Vala中，管理这种引用计数是自动化的，如果编程者使用语言内建引用类型而非普通指针的话。唯一需要当心的是避免生成引用环，因为在这种情况下内存管理系统不能正确工作，此时需要使用Vala自带的week关键字标注弱引用解决。 对于不支持引用计数的类型，Vala也支持按照生命周期自动释放内存的非引用计数内存管理；Vala还可以通过指针手工内存管理。 Vala意图提供但现存C库的运行时间访问，特别是基于GObject的库，而不需要运行时绑定。要通过Vala使用一个由C语言编写的库，全部所需就是一个API文件（.vapi），包含采用Vala语法的类和方法声明。但是不支持C++库。目前在Vala的每次发行中，都包括了GTK以及大部份的GNU项目和GNOME平台的vapi文件。还有用Vala写的一个库叫做Gee，为常用数据结构提供基于GObject的接口和类。 为从用其他语言比如C#写的应用访问Vala库，写绑定生成器也应当是容易的，因为Vala解析器被写为一个库，所以所有运行时信息在生成一个绑定的时候都是可获得到的。 Vala的开发工具近些年来有了显著改进。下面是具有支持Vala编程的插件的一些流行IDE和文本编辑器： GNOME Builder Visual Studio Code，具有Vala插件 Vim，具有arrufat/vala.vim插件 Emacs，具有vala-mode Atom Geany Kate 目前，有两个活跃开发的语言服务器为Vala提供了代码智能： vala-lang/vala-language-server，设计用于支持LSP的任何编辑器，包括VSCode、vim和GNOME Builder。 esodan/gvls，目前是Vala在GNOME Builder中的缺省语言服务器，它对支持LSP的任何编辑器提供支持。 目前，有一些建造系统支持Vala，包括Automake、CMake、Meson等。 对Vala程序的调试可以使用GDB或LLDB（英语：LLDB (debugger)）。对于IDE： GNOME Builder拥有通过GDB的对Vala的内建调试支持。 Visual Studio Code拥有对GDB和LLDB（英语：LLDB (debugger)）的扩展，比如cpptools和CodeLLDB。 一个简单的“Hello world”程序： void main () { print ("Hello World\n"); } 下面是更复杂的一个版本，表现了Vala的一些面向对象的特征： class HelloWorld: Object { private uint year = 0; public HelloWorld () { } public HelloWorld.with_year (int year) { if (year > 0) this.year = year; } public void greeting () { if (year == 0) print ("Hello World\n"); else /* Strings prefixed with '@' are string templates. */ print (@"Hello World, $(this.year)\n"); } } void main (string[] args) { var helloworld = new HelloWorld.with_year (2021); helloworld.greeting (); } 因为在GObject库的情况下，Vala不支持多重继承，但是Vala中的类可以实现任何数量的接口，它可以包含它们的方法的缺省实现。下面一段代码展示具有缺省实现的Vala接口（有时称为mixin）： using GLib; interface Printable { public abstract string print (); public virtual string pretty_print () { return "Please " + print (); } } class NormalPrint: Object, Printable { string print () { return "don't forget about me"; } } class OverridePrint: Object, Printable { string print () { return "Mind the gap"; } public override string pretty_print () { return "Override"; } } void main (string[] args) { var normal = new NormalPrint (); var overridden = new OverridePrint (); print (normal.pretty_print ()); print (overridden.pretty_print ()); } 下面是基本例子，展示如何定义一个信号于非紧凑（compact）的一个类中，它拥有用Vala通过GLib建造的一个信号系统。接着注册回调函数到这个类的一个实例的这个信号。这个实例可以发送这个信号，而连接到这个实例的每个回调函数（也叫做处理器），将安它们连接上的次序来调用： class Foo { public signal void some_event (); // 定义一个信号 public void method () { some_event (); // 发送这个信号（回调得以调用） } } void callback_a () { print ("Callback A\n"); } void callback_b () { print ("Callback B\n"); } void main () { var foo = new Foo (); foo.some_event.connect (callback_a); // 连接回调函数 foo.some_event.connect (callback_b); foo.method (); } 在Vala中新线程是代码的一部份，比如要求在运行时间并发执行的一个函数。新线程的创建和同步是用时GLib中的Thread类完成的，它在创建新线程时接受一个函数作为参数，如下面（非常简化的）例子所示： int question(){ // 一些print操作 for (var i = 0; i < 3; i++){ print ("."); Thread.usleep (800000); stdout.flush (); } return 42; } void main () { if (!Thread.supported ()) { printerr ("Cannot run without thread support.\n"); return; } print ("The Ultimate Question of Life, the Universe, and Everything"); // 泛型参数是返回值的类型 var thread = new Thread<int> ("question", question); print(@" $(thread.join ())\n"); } 使用GTK来创建一个图形用户界面的"Hello, World!"程序： int main (string[] args) { var app = new Gtk.Application ( "com.example.App", ApplicationFlags.DEFAULT_FLAGS ); app.activate.connect (() => { var win = new Gtk.ApplicationWindow (app) { title = "Hello, World!", default_width = 350, default_height = 70 }; var label = new Gtk.Label ("Hello, World!"); win.child = label; win.present (); }); return app.run (args); } 在GTK 4平台上，需要以下命令来编译这一示例: valac --pkg gtk4 hellogtk.vala Genie，基于Vala编译器的具有近似Python语法的一种语言。 Shotwell，用Vala写的图片组织器。 Geary（英语：Geary (e-mail client)），用Vala写的邮件客户端。 elementary OS，具有大多用Vala编程的桌面环境的Linux发行版。 Budgie，大多用Vala编程的Linux桌面环境。 Release 0.57.0. 2023年4月11日 [2023年5月4日].  Vala· GitLab. GNOME. [16 March 2021]. （原始内容存档于2022-05-08）.  Vala Releases. Vala Project. [2021-03-18]. （原始内容存档于2022-03-08）.  Vala's Memory Management Explained. [2022-03-08]. （原始内容存档于2022-05-05）.  Projects/Vala/ReferenceHandling - GNOME Wiki!. wiki.gnome.org. [2023-01-18]. （原始内容存档于2022-05-05）.  Libgee on Gitlab. [2022-03-08]. （原始内容存档于2022-03-24）.  Coding in Vala with Visual Studio Code. [2021-03-17]. （原始内容存档于2022-03-08）.  Coding in Vala with the Vim Text Editor. [2021-03-17]. （原始内容存档于2022-03-08）.  Enable Vala syntax highlighting and code browser support in GNU Emacs. [2021-03-17]. （原始内容存档于2021-05-12）.  Vala Language Server, Vala, 2023-01-13 [2023-01-18], （原始内容存档于2022-09-25）  esodan/gvls on GitLab. [2021-03-17]. （原始内容存档于2022-03-08）.  Vala Tools. [2021-03-29]. （原始内容存档于2022-01-06）.  The Vala Programming Language（页面存档备份，存于互联网档案馆）, on GNOME Live! Vala 语言书籍《Introducing Vala Programming》 （Apress （页面存档备份，存于互联网档案馆） / Amazon （页面存档备份，存于互联网档案馆）） 面向 Java 开发者的Vala 特性介绍 （页面存档备份，存于互联网档案馆） 面向 C# 开发者的 Vala 特性介绍 （页面存档备份，存于互联网档案馆） Benchmark of Vala versus C# and C（页面存档备份，存于互联网档案馆） Vala 语言编程规范（Geary版） （页面存档备份，存于互联网档案馆） Vala 的语言服务器（Language Server Protocol）项目： VLS （页面存档备份，存于互联网档案馆）， GVLS （页面存档备份，存于互联网档案馆） Vala 语言社区： The Vala community on GitHub （页面存档备份，存于互联网档案馆） Vala 语言案例列表 （页面存档备份，存于互联网档案馆） Vala 语言开发的数据库管理工具： DBKangaroo （页面存档备份，存于互联网档案馆） Vala 语言库：官方库 Vala 语言库：第三方库 （页面存档备份，存于互联网档案馆）