正如已经看到的,数据模型的基本结构是树状的。 这棵树可以很复杂,并且可以有很大的深度,比如:
(root) | +- animals | | | +- mouse | | | | | +- size = "small" | | | | | +- price = 50 | | | +- elephant | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- python | | | +- size = "medium" | | | +- price = 4999 | +- message = "It is a test" | +- misc | +- foo = "Something"
上图中的变量扮演目录的角色(比如 root,
animals
, mouse
,
elephant
, python
,
misc
) 被称为 hashes (哈希表或哈希,译者注)。哈希表存储其他变量(被称为
子变量),
它们可以通过名称来查找(比如 "animals",
"mouse" 或 "price")。
存储单值的变量
(size
, price
,
message
和 foo
) 称为
scalars (标量,译者注)。
如果要在模板中使用子变量,
那应该从根root开始指定它的路径,每级之间用点来分隔开。要访问 mouse
的
price
,要从root开始,首先进入到 animals
,之后访问
mouse
,最后访问 price
。就可以这样来写
animals.mouse.price
。
另外一种很重要的变量是 sequences (序列,译者注)。
它们像哈希表那样存储子变量,但是子变量没有名字,它们只是列表中的项。
比如,在下面这个数据模型中, animals
和
misc.fruits
就是序列:
(root) | +- animals | | | +- (1st) | | | | | +- name = "mouse" | | | | | +- size = "small" | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = "elephant" | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = "python" | | | +- size = "medium" | | | +- price = 4999 | +- misc | +- fruits | +- (1st) = "orange" | +- (2nd) = "banana"
要访问序列的子变量,可以使用方括号形式的数字索引下标。
索引下标从0开始(从0开始也是程序员的传统),那么第一项的索引就是0,
第二项的索引就是1等等。要得到第一个动物的名称的话,可以这么来写代码
animals[0].name
。要得到 misc.fruits
中的第二项(字符串"banana"
)可以这么来写
misc.fruits[1]
。(实践中,通常按顺序遍历序列,而不用关心索引,
这点会在 后续介绍。)
标量类型可以分为如下的类别:
-
字符串:就是文本,也就是任意的字符序列,比如上面提到的 ''m'', ''o'', ''u'', ''s'', ''e''。比如
name
和size
也是字符串。 -
数字:这是数值类型,就像上面的
price
。 在FreeMarker中,字符串"50"
和数字50
是两种完全不同的东西。前者是两个字符的序列 (这恰好是人们可以读的一个数字),而后者则是可以在数学运算中直接被使用的数值。 -
日期/时间: 可以是日期-时间格式(存储某一天的日期和时间), 或者是日期(只有日期,没有时间),或者是时间(只有时间,没有日期)。
-
布尔值:对应着对/错(是/否,开/关等值)类似的值。 比如动物可以有一个
protected
(受保护的,译者注) 的子变量, 该变量存储这个动物是否被保护起来的值。
总结:
-
数据模型可以被看成是树形结构。
-
标量用于存储单一的值。这种类型的值可以是字符串,数字,日期/时间或者是布尔值。
-
哈希表是一种存储变量及其相关且有唯一标识名称的容器。
-
序列是存储有序变量的容器。存储的变量可以通过数字索引来检索,索引通常从0开始。
还有一些其它更为高级的类型,在这里我们并没有涉及到,比如方法和指令。