2024-02-05更新。

草稿

基本配置

在Pkl教程的第一部分中,你将熟悉Pkl的语法和基本结构。你还将学习调用Pkl的不同方法以生成不同的格式。

基本价值观

考虑下面这个 Pkl 文件示例。intro.pkl

笔记
name = "Pkl: Configure your Systems in New Ways" attendants = 100 isInteractive = true amountLearned = 13.37

在这个文件上运行Pkl会给出

笔记
$ pkl eval /Users/me/tutorial/intro.pkl name = "Pkl: Configure your Systems in New Ways" attendants = 100 isInteractive = true amountLearned = 13.37

它可能看起来什么都没有发生。然而,Pkl告诉你它接受了输入。换句话说,你现在知道intro.pkl中没有任何错误。你可以要求Pkl使用-f选项以不同格式打印此配置。例如,JSON格式:

笔记
$ pkl eval -f json /Users/me/tutorial/intro.pkl { "name": "Pkl: Configure your Systems in New Ways", "attendants": 100, "isInteractive": true, "amountLearned": 13.37 }

或者属性列表格式:

笔记
$ pkl eval -f plist /Users/me/tutorial/intro.pkl <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 1 "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>name</key> <string>Pkl: Configure your Systems in New Ways</string> <key>attendants</key> <integer>100</integer> <key>isInteractive</key> <true/> <key>amountLearned</key> <real>13.37</real> </dict> </plist>

请注意,Pkl 为配置中的值生成了<string>、<integer>、<true/> 和 <real>。这意味着它不仅正确地推导出了字面值的类型,并且将这些类型转换为 PropertyList 中对应的元素。第三部分将更详细地讨论类型。

结构:类,对象,模块

一种配置通常不仅仅需要基本值。通常,你需要某种(层次)结构。Pkl提供了用于此目的的不可变对象。对象有三种成员:属性、元素和条目。首先,来看一下对象及其成员的语法。

属性

笔记
simpleObjectWithProperties.pkl
笔记
bird { ① name = "Common wood pigeon" ② diet = "Seeds" taxonomy { ③ species = "Columba palumbus" } }

① 这定义了bird为一个对象。② 对于原始值,Pkl采用等号(=)语法(稍后将会详细介绍这一点)。③ 就像是bird {,但这是为了显示对象可以嵌套。这定义了一个称为bird的对象,它包含三个具名属性:name(名称)、diet(饮食)和taxonomy(分类学)。其中前两个属性是字符串,但taxonomy是另一个对象。这意味着对象中的属性可以有不同的类型,而且对象是可以嵌套的。

元素

当然,你不总是能为配置中的每个独立结构命名。如果你想拥有“一堆东西”但又不知道有多少个怎么办?Pkl为此目的提供了元素。元素是对象成员,就像属性一样。你通过名字索引属性,通过整数索引元素。你可以将只包含元素的对象视为数组。与许多语言中的数组一样,你可以使用方括号来访问一个元素,例如,myObject[42]。你通过仅书写一个表达式来写入一个元素。Pkl根据对象中已有的元素数量推导出索引。例如:simpleObjectsWithElements.pkl。

笔记
exampleObjectWithJustIntElements { 100 ① 42 } exampleObjectWithMixedElements { "Bird Breeder Conference" (2000 + 23) ② exampleObjectWithJustIntElements ③ }

① 当你仅仅写下一个值(没有名称时),你描述的是一个元素。② 元素不必是字面上的值;它们可以是任意表达式。③ 元素真的可以是任何值,不仅仅是原始值。

条目

对象可以具有一种额外的成员;条目。和属性一样,条目也是“命名”的(技术上说是有键的)。与属性不同,名字在声明时不需要已知。当然,我们需要一种语法来区分条目和属性。你可以通过使用方括号将条目的“名称”括起来来编写(“名称”加引号,因为名称不需要是字符串;任何值都可以索引条目)。simpleObjectsWithEntries.pkl

笔记
pigeonShelter { ["bird"] { ① name = "Common wood pigeon" diet = "Seeds" taxonomy { species = "Columba palumbus" } } ["address"] = "355 Bird St." ② 3 } birdCount { [pigeonShelter] = 42 ③ }

① 与属性不同的是键的表示法:[<expression>]。 ② 和属性一样,条目可以是原始值或对象。 ③ 任何对象都可以用作条目的键。

混合成员

在迄今为止的例子中,你已经看到了具有属性的对象、具有元素的对象和具有条目的对象。这些对象成员可以自由混合。mixedObject.pkl

笔记
mixedObject { name = "Pigeon" lifespan = 8 "wing" "claw" ["wing"] = "Not related to the _element_ \"wing\"" 42 extinct = false [false] { description = "Construed object example" } }

请注意,在这一个对象中属性(名字、寿命和是否灭绝)、元素("翅膀"、"爪子"、42)和条目("翅膀",false)是如何混合在一起的。你无需按种类对它们进行排序,也不需要使用(其他)特殊的语法。

集合

对象成员的这种自由混合可能会变得令人困惑。此外,目标格式通常要严格得多。在下面的例子中,你会看到尝试从mixedObject生成JSON时会发生什么:

笔记
$ pkl eval -f json /Users/me/tutorial/mixedObject.pkl –– Pkl Error –– Cannot render object with both properties/entries and elements as JSON. Object: "Pigeon" 89 | text = renderer.renderDocument(value) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L90)

这就是为什么Pkl有两种特殊类型的对象,即只包含元素的列表和只包含条目的映射。列表和映射都是“仅仅是对象”,因此,它们不需要除了对象本身的语法: collections.pkl

笔记
birds { ① "Pigeon" "Parrot" "Barn owl" "Falcon" } habitats { ② ["Pigeon"] = "Streets" ["Parrot"] = "Parks" ["Barn owl"] = "Forests" ["Falcon"] = "Mountains" }

包含四个元素的列表。包含四个条目的映射。注意,技术上,定义鸟类和栖息地的正确方式是使用新的列表 {…} 和新的映射 {…}。在本教程的第三部分中,你将看到这些意味着什么。当你将此配置渲染为JSON时,一切正常:

笔记
{ "birds": [ "Pigeon", "Parrot", "Barn owl", "Falcon" ], "habitats": { "Pigeon": "Streets", "Parrot": "Parks", "Barn owl": "Forests", "Falcon": "Mountains" } }

特别注意,你将列表渲染成了一个JSON数组。当你用整数5来索引列表时,你是在引用相应位置的元素(从0开始)。例如:indexedListing.pkl

导致

笔记
birds { "Pigeon" "Parrot" "Barn owl" "Falcon" } relatedToSnowOwl = "Barn owl"

锻炼

给定以下JSON片段(取自W3C示例),编写生成此JSON的.pkl文件。

笔记
{ "name": "Common wood pigeon", "lifespan": 8, "friends": { "bird1": "Parrot", "bird2": "Albatross", "bird3": "Falcon" } }

出于某种原因,我们决定我们不再需要不同鸟类的birdX名称;我们只需要将它们作为一个数组。将你对上一个问题的解决方案改为产生以下JSON结果:

笔记
{ "name": "Common wood pigeon", "lifespan": 8, 6 "birds": ["Parrot", "Barn owl", "Falcon"] }