学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net

模板开发指南——数值、类型

1.基本内容

1.1 什么是数值?

  正如你知道的,来自于每天所使用的数字,比如16,0.5等这些用语就是 数值 的示例,也就是数字。在计算机语言中, 这些用语有着更广泛的含义,比如数值并不一定是数字类型值,比如面这个数据模型:

(root)
 |
 +- user = "Big Joe"
 |
 +- today = Jul 6, 2007
 |
 +- todayHoliday = false
 |
 +- lotteryNumbers
 |   |
 |   +- (1st) = 20
 |   |
 |   +- (2st) = 14
 |   |
 |   +- (3rd) = 42
 |   |
 |   +- (4th) = 8
 |   |
 |   +- (5th) = 15
 |
 +- cargo
     |
     +- name = "coal"
     |
     +- weight = 40

  变量 uservalue 是"Big Joe"(字符串), todayvalue 是 Jul 6, 2007 (日期),todayHolidayvalue 是false(布尔值,比如yes/no等值)。 lotteryNumbersvalue 是包含20,14, 42, 8, 15的序列。当然在这种意义上, lotteryNumbers 是多值类型。它 包含 多个值(比如,其中的第二项的 value 是14),但是 lotteryNumbers 本身还是单值。它就像一个装有其它很多东西的盒子 (或称之为容器,译者注),但盒子作为整体还是视作单独的。最后还有一个数值 cargo,它的 value 是一个哈希表 (也是类似盒子一样的东西)。所以说,数值就是存储在变量中的(比如,在 usercargocargo.name 中)的那个东西。但是, 不需要存储于变量之中的数值也可以称之为数值,比如下面的数字100:

<#if cargo.weight < 100>Light cargo</#if>

  当模板被执行时,计算出的临时结果也称为数值,比如这里的20和120(它会打印120):

${cargo.weight / 2 + 100}

  这里针对最后一种表示进行解释:有两个数,40(货物的重量)和2, 相除的结果是20,这是一个新计算出来的数值。然后,把它和100相加, 那么120就计算出来了,接着就打印出来。 (${...}),之后模板继续向下执行, 直到所有结果都计算出来。

  现在你应该能体会到数值这个词的含义了。

1.2 什么是类型?

  数值中非常重要的一个概念就是类型。比方说,变量 user 的类型是字符串,变量 lotteryNumbers 的类型是序列。数值的类型这个概念非常的重要,因为它决定了这些数值可以在哪里使用的最大限度。 比如说,使用 ${user / 2} 就是错误的,但是使用 ${cargo.weight / 2} 就能计算出结果,为20, 因为算术中的除法仅对数字类型的值有效,而不能用于字符串。 仅当 cargo 是一个哈希表变量时,表达式 cargo.name 才可以使用点。也可以用 <#list ...> 指令来遍历序列。而 <#if ...> 指令的条件只能是布尔值等。

注意:

  这里说一点点的术语:称 "布尔" 或 "布尔值" 或 "布尔类型" 都是相同的含义。

  数值同时也可以含有多种类型,尽管很少这么使用。看一下下面这个数据模型 mouse 它本身就又是字符串,又是哈希表:

(root)
 |
 +- mouse = "Yerri"
     |
     +- age = 12
     |
     +- color = "brown"

  如果用上面的数据模型合并到下面的模板中:

 ${mouse}       <#-- uses mouse as a string -->
 ${mouse.age}   <#-- uses mouse as a hash -->
 ${mouse.color} <#-- uses mouse as a hash -->

  将会输出:

 Yerri
 12
 brown

1.3 数据模型是哈希表

  注意观察每个数据模型的例子你也许能发现:被"(root)"所标识的内容就是哈希表类型的值。 当编写如 user 这样的代码时,那就意味着要把"user"变量存储在哈希表的根上。 就像编写 root.user一样,这里但并没有名"root"为的变量, 那么这就起不到任何作用了。

  某些人也许会被这种数据模型的例子所困惑,也就是说,根哈希表包含更多的哈希表或序列 (lotteryNumbers and cargo)。其它就没有更特殊的内容了。 哈希表包含其他变量,那些变量包含其它值,这些数值可以是字符串,数字等变量, 当然也可以是哈希表或序列变量。最初我们解释过的,就像字符串和数字, 序列或哈希表也是一种值的表示形式。

2.类型

2.1 标量

  标量是最基本,最简单的数值类型,它们可以是:

  • 字符串:表示简单的文本,例如:产品的名称。

    如果想在模板中直接给出字符串值,而不是使用数据模型中的变量, 那么将文本内容写在引号内即可,比如 "green mouse"'green mouse'

  • 数值:比如说,产品的价格。 整数和非整数是不区分的;只有单一的数字类型。比如使用了计算器, 计算3/2的结果是1.5而不是1。

    如果要在模板中直接给出数字的值,那么可以这么来写: 150-90.050.001

  • 布尔值:布尔值代表了逻辑上的对或错(是或否)。比如:用户是否登录了。 典型的应用是使用布尔值作为 if 指令的条件, 比如 <#if loggedIn >...</#if> 或者 <#if price == 0>...</#if>; 后面这个 price == 0 部分的结果就是布尔值。

    在模板中可以使用保留字 truefalse 来指定布尔值。

  • 日期:日期变量可以存储和日期/时间相关的数据。 一共有三种变化:

    • 日期:精确到天的日期,没有时间部分。比如April 4, 2003。

    • 时间:精确到毫秒,没有日期部分。比如10:19:18 PM。

    • 日期-时间(有时也被称为"时间戳"),比如April 4,2003 10:19:18 PM。 有日期和时间两部分,时间部分的存储精确到毫秒。

    不幸的是,受到Java平台的限制,FreeMarker 有时是不能决定日期的部哪分被使用 (也就是说,是日期-时间格式,日期格式还是时间格式)。 这个问题的解决方法是一个的高级话题,将会在 后续章节讨论。

    模板中直接定义日期数值是可以的,但这也是高级话题,将会在 后续章节 中进行解释。

  要记住,FreeMarker区别字符串,数字,布尔值和日期类型的值。比如, 字符串 "150" 看起来很像数字 150, 字符串只是字符的任意序列,不能将它用于计算目的,也不能和其它数字进行比较等等。

2.2 容器

  这些值存在的目的是为了包含其他变量;它们只是容器。 它们包含的变量通常视为 subvariables (子变量)。容器的类型有:

  • 哈希表:每个子变量都可以通过一个唯一的名称来查找。 这个名称是不受限制的字符串。哈希表 并不确定其中子变量的顺序。 也就是说没有第一个子变量,第二个子变量这样的说法等;变量仅仅是通过名称来访问的。 (就像Java语言中的HashMap一样,是实现了Hash算法的Map,不记录内部元素的顺序, 仅仅通过名称来访问。)

  • 序列:每个子变量通过一个整数来标识。第一个子变量的标识符是0, 第二个是1,第三个是2,这样来类推,而且子变量是有顺序的。这些数次通常被称为 indexes(索引)。序列通常比较密集,也就是所有的索引, 包括最后一个子变量的,它们和子变量都是相关联的,但不是绝对必要的。 子变量的类型也并不需要完全一致。

  • 集合:从模板设计者角度来看,集合是有限制的序列。不能获取集合的大小, 也不能通过索引取出集合中的子变量,但是它们仍然可以通过 list 指令来遍历。

  请注意,一个值也可有多种类型,对于一个值可能同时存在哈希表和序列这两种类型,这时, 该变量就支持索引和名称两种访问方式。 不过容器基本是当作哈希表或者序列来使用的,而不是两者同时使用。

  尽管存储在哈希表,序列(集合)中的变量可以是任意类型的, 这些变量也可以是哈希表,序列(或集合)。这样就可以构建任意深度的数据结构。

  数据模型本身(最好说成是它的根root)也是哈希表。

2.3 子程序

2.3.1方法和函数

  当一个值是方法或函数的时候,那么它就可以计算其他值,结果取决于传递给它的参数。

  这部分是对程序员来说的:方法/函数是一等类型值, 就像函数化的编程语言。也就是说函数/方法也可以是其他函数/方法的参数或者返回值, 并可以把它们定义成变量等。

  假设程序员在数据模型中放置了一个方法变量 avg, 该变量用来计算数字的平均值。如果给定3和5作为参数,访问 avg 时就能得到结果4。

  方法的使用将会在 后续章节 中进行解释, 下面这个示例会帮助我们理解方法的使用:

 The average of 3 and 5 is: ${avg(3, 5)}
 The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
 The average of the price of a python and an elephant is:
 ${avg(animals.python.price, animals.elephant.price)}

  将会输出:

 The average of 3 and 5 is: 4
 The average of 6 and 10 and 20 is: 12
 The average of the price of a python and an elephant is:
 4999.5

  那么方法和函数有什么区别呢?这是模板作者所关心的, 它们没有关系,但也不是一点关系都没有。 方法是来自于数据模型 (它们反射了Java对象的方法) 而函数是定义在模板内的 (使用 function 指令 -- 也是高级话题),但二者可以用同一种方式来使用。

2.3.2 用户自定义指令

  这种类型的值可以作为用户自定义指令(换句话说,就是FreeMarker的标签) 用户自定义指令是一种子程序,一种可以复用的模板代码段。但这也是一个高级话题, 将会在 后续章节 中进行解释。

  这部分是对程序员来说的: 用户自定义指令(比如宏)也是一等值类型,就像函数/方法一样。

  这里仅仅对用户自定义指令有一个认识即可(如果现在还不能理解可以先忽略它)。 假设现在有一个变量 box,它的值是用户自定义的指令, 用来打印一些特定的HTML信息,包含标题和一条信息。那么, box 变量就可以在模板中使用(示例如下):

 <@box title="Attention!">
   Too much copy-pasting may leads to
   maintenance headaches.
 </@box>

2.3.3 函数/方法和用户自定义指令的比较

   如果要使用函数/方法或自定义指令去实现一些东西的时候, 二者之间的选择是两难的。按经验来说,如果能够实现需求, 请先用自定义指令而不要用函数/方法。如果:

  • ... 输出(返回值)的是标记(HTML,XML等)。 主要原因是函数的返回结果可以自动进行XML转义(这是因为 ${...} 的特性), 而用户自定义指令的输出则不是 (这是因为 <@...> 的特性所致; 它的输出假定是标记,因此已经转义过了)。

  • ... 副作用也是很重要的一点,它没有返回值。 例如一个指令的目的是往服务器日志中添加一条。 (事实上不能得到自定义指令的返回值, 但有些反馈的类型是有可能设置非本地变量的。)

  • ... 会进行流程的控制(就像 listif 指令那样)。但是不能在函数/方法上这么做。

  在模板中,FreeMarker不知道的Java对象的方法通常是可以作为方法来使用的, 而不用考虑Java对象方法本身的特性,因为在这里没有其他的选择。

2.4 其它

2.4.1 结点

  结点变量代表了树状结构中的一个结点,而且通常是配合 XML 处理的,这是专业而且更高级的话题。

  这里我们仅对 高级用户 进行一个概要说明: 结点和存储在其他结点中的序列很相似,通常也被当作为子结点。结点存储它所在的容器结点的引用, 也就是父结点。结点的主要作用是拓扑信息;其它数据必须通过使用多类型的值来存储。 就像一个值可以同时是一个结点和一个数字,这样它存储的数字可以作为如支付额来使用。 除了拓扑信息,结点也可以存储一些元信息(即metadata,译者注):如结点名称,它的类型(字符串), 命名空间(字符串)。若一个结点象征XHTML文档中的 h1 元素, 那么它的名字可以是 "h1",类型可以是 "element", 命名空间可以是 "http://www.w3.org/1999/xhtml"。但对于数据模型设计者来说, 这些元信息,还有如何来使用它们又有什么意义呢。检索拓扑信息和元信息的方法将会在 后续章节 中来说明(这里可以先不用理解它们)。

译自 Email: ddekany at users.sourceforge.net

freeMarker(三)——模板开发指南之数值、类型的更多相关文章

  1. FreeMarker:模板开发指南

    ylbtech-FreeMarker:模板开发指南 1.返回顶部 1. Section Contents 入门 模板 + 数据模型 = 输出 数据模型一览 模板一览 数值,类型 基本内容 类型 模板 ...

  2. FreeMarker模板开发指南知识点梳理

    freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...

  3. freeMarker(四)——模板开发指南之模板

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 模板开发指南之模板 1. 总体结构 实际上用程序语言编写的程序就是模板 ...

  4. freeMarker(五)——模板开发指南补充知识

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 模板开发指南补充知识 1. 自定义指令 自定义指令可以使用 macro ...

  5. freeMarker(二)——模板开发指南之入门

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 模板开发指南-入门  1.模板+数据模型=输出 假设在一个在线商店的应 ...

  6. freeMarker(八)——程序开发指南之配置(Configuration)

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.基本内容 配置(configuration)就是 freemark ...

  7. freeMarker(六)——程序开发指南入门

    学习笔记,选自freeMarker中文文档,译自 Email: ddekany at users.sourceforge.net 1.创建Configuration实例 首先,你应该创建一个 free ...

  8. 二、FreeMarker 模版开发指南 第二章 数值和类型

    章节内容如下:   基本内容 类型 一.基本内容 简介 什么是数值? 什么是类型? 数据模型是哈希表 a.简介 理解数值和类型的概念是理解数据模型的关键所在.然而,数值和类型的概念并不局限于数据模型, ...

  9. [翻译]现代java开发指南 第三部分

    现代java开发指南 第三部分 第三部分:Web开发 第一部分,第二部分,第三部分 =========================== 欢迎来到现代 Java 开发指南第三部分.在第一部分中,我们 ...

随机推荐

  1. 基于Linux整形时间的常用计算思路

    上一次分享了Linux时间时区详解与常用时间函数,相信大家对Linux常见时间函数的使用也有了一定的了解,在工作中遇到类似获取时间等需求的时候也一定能很好的处理.本文基于Linux整形时间给出一些简化 ...

  2. 【JavaScript】BOM和DOM

    在第一篇JavaScript视频总结博客中.是对JavaScript做了一个宏观的认识.当中,不知道大家可否还记得.JavaScript的核心部分包含哪些? JavaScript的核心部分主要包含三个 ...

  3. zabbix server is not running解决办法

    正常安装完zabbix后,登录后zabbix监控报错zabbix server is not running: the information displayed may not be current ...

  4. 九度OJ 1338:角斗士 (递归、DP)

    时间限制:3 秒 内存限制:32 兆 特殊判题:否 提交:213 解决:66 题目描述: 角斗士是古罗马奴隶社会的一种特殊身份的奴隶,他们的职责是在角斗场上进行殊死搏斗,为了人们提供野蛮的娱乐.他们的 ...

  5. polynomial time

    https://en.wikipedia.org/wiki/Time_complexity#Polynomial_time An algorithm is said to be of polynomi ...

  6. mydql练习答案

    .查询“生物”课程比“物理”课程成绩高的所有学生的学号: 思路: 获取所有有生物课程的人(学号,成绩) - 临时表 获取所有有物理课程的人(学号,成绩) - 临时表 根据[学号]连接两个临时表: 学号 ...

  7. hibernate多对多关系配置

    一.创建用户,角色实体类. 一名用户可以有多个角色.一个角色可以对于多名用户. 用户实体类 public class User { private int uId; private String uN ...

  8. 坑爹的Hibernate 映射文件错误提示org.xml.sax.SAXParseException

    今天整整一个上午都在和hibernate做斗争,早上一来,继续昨天的项目开发,发现spring项目不能启动,从错误中看是hibernate错误,多半是hibernate配置有错误,关键是错误提示中显示 ...

  9. Linux命令:grep,报错Binary file (standard input) matches

    在Linux使用grep命令,从文件中抓取显示特定的信息,如下: cat 文件名 | grep 特定条件 --->   cat xxxx | grep 12345 结果报错:Binary fil ...

  10. html5 说明

    # 客户端储存历程 远古时期 cookies的用法和缺陷 userdata   HTML5时代 localstorage application cache 离线缓存 indexedeDB 客户端数据 ...