第 12 章 语言扩展

12 属性

(在 OCaml 4.02 中引入,在 4.03 中添加了除表达式外的构造的中缀表示法)

属性是语法树的“装饰”,类型检查器大多会忽略它们,但外部工具可以使用它们。属性由一个标识符和一个有效负载组成,有效负载可以是结构、类型表达式(以 : 为前缀)、签名(以 : 为前缀)或模式(以 ? 为前缀),后面可以选择跟随一个 when 子句

attr-id::= 小写标识符
   大写标识符
   attr-id.attr-id
 
attr-payload::=[ module-items ]
   :typexpr
   : [ specification ]
   ?pattern [whenexpr]
 

属性的第一种形式附加在“代数”类别上,使用后缀表示法

attribute::= [@attr-idattr-payload]
 
expr::= ...
 exprattribute
 
typexpr::= ...
 typexprattribute
 
pattern::= ...
 patternattribute
 
module-expr::= ...
 module-exprattribute
 
module-type::= ...
 module-typeattribute
 
class-expr::= ...
 class-exprattribute
 
class-type::= ...
 class-typeattribute
 

这种形式的属性也可以插入到多态变体类型表达式中的 `tag-name 后面 (tag-spec-firsttag-spectag-spec-full) 或 method-type 中的 method-name 后面。

相同的语法形式也用于将属性附加到类型声明中的标签和构造函数

field-decl::=[mutable] field-name:poly-typexpr { attribute }
 
constr-decl::=(constr-name ∣ ()) [ ofconstr-args ] { attribute }
 

注意:当标签声明后面跟着分号时,属性也可以放在分号后面(在这种情况下,它们会与之前指定的属性合并)。

属性的第二种形式附加到“块”上,例如类型声明、类字段等

item-attribute::= [@@attr-idattr-payload]
 
typedef::= ...
 typedefitem-attribute
 
exception-definition::= exceptionconstr-decl
 exceptionconstr-name=constr
 
module-items::=[;;] ( definition ∣ expr { item-attribute } ) { [;;] definition ∣ ;;expr { item-attribute } } [;;]
 
class-binding::= ...
 class-bindingitem-attribute
 
class-spec::= ...
 class-specitem-attribute
 
classtype-def::= ...
 classtype-defitem-attribute
 
definition::= let [rec] let-binding { andlet-binding }
 externalvalue-name:typexpr=external-declaration { item-attribute }
 type-definition
 exception-definition { item-attribute }
 class-definition
 classtype-definition
 modulemodule-name { (module-name:module-type) } [ :module-type ]  =module-expr { item-attribute }
 moduletypemodtype-name=module-type { item-attribute }
 openmodule-path { item-attribute }
 includemodule-expr { item-attribute }
 modulerecmodule-name:module-type=module-expr { item-attribute }  { andmodule-name:module-type=module-expr  { item-attribute } }
 
specification::= valvalue-name:typexpr { item-attribute }
 externalvalue-name:typexpr=external-declaration { item-attribute }
 type-definition
 exceptionconstr-decl { item-attribute }
 class-specification
 classtype-definition
 modulemodule-name:module-type { item-attribute }
 modulemodule-name { (module-name:module-type) } :module-type { item-attribute }
 moduletypemodtype-name { item-attribute }
 moduletypemodtype-name=module-type { item-attribute }
 openmodule-path { item-attribute }
 includemodule-type { item-attribute }
 
class-field-spec::= ...
 class-field-specitem-attribute
 
class-field::= ...
 class-fielditem-attribute
 

属性的第三种形式出现在模块或类子语言中的独立结构或签名项中。它们没有附加到语法树中的任何特定节点

floating-attribute::= [@@@attr-idattr-payload]
 
definition::= ...
 floating-attribute
 
specification::= ...
 floating-attribute
 
class-field-spec::= ...
 floating-attribute
 
class-field::= ...
 floating-attribute
 

(注意:与上面语法描述的相反,item-attributes 不能附加到 class-field-specclass-field 中的这些浮动属性上。)

也可以使用中缀语法指定属性。例如

let[@foo] x = 2 in x + 1          === (let x = 2 [@@foo] in x + 1)
begin[@foo][@bar x] ... end       === (begin ... end)[@foo][@bar x]
module[@foo] M = ...              === module M = ... [@@foo]
type[@foo] t = T                  === type t = T [@@foo]
method[@foo] m = ...              === method m = ... [@@foo]

对于 let,属性应用于每个绑定

let[@foo] x = 2 and y = 3 in x + y === (let x = 2 [@@foo] and y = 3 in x + y)
let[@foo] x = 2
and[@bar] y = 3 in x + y           === (let x = 2 [@@foo] and y = 3 [@@bar] in x + y)

12.1 内置属性

某些属性会被类型检查器理解

module X = struct [@@@warning "+9"] (* 在此结构中本地启用警告 9 *)end [@@deprecated "请使用模块 'Y' 代替。"] let x = begin[@warning "+9"] […] end type t = A | B [@@deprecated "请使用类型 's' 代替。"]
let fires_warning_22 x = assert (x >= 0) [@ppwarning "TODO: 稍后删除此内容"]
Warning 22 [preprocessor]: TODO: 稍后删除此内容
let rec is_a_tail_call = function | [] -> () | _ :: q -> (is_a_tail_call[@tailcall]) q let rec not_a_tail_call = function | [] -> [] | x :: q -> x :: (not_a_tail_call[@tailcall]) q
Warning 51 [wrong-tailcall-expectation]: 预期尾调用
let f x = x [@@inline] let () = (f[@inlined]) ()
type fragile = | Int of int [@warn_on_literal_pattern] | String of string [@warn_on_literal_pattern]
let fragile_match_1 = function | Int 0 -> () | _ -> ()
Warning 52 [fragile-literal-pattern]: 代码不应依赖于此构造函数参数的实际值。它们仅供信息参考,并且在将来版本中可能会更改。(请参阅手册第 13.5.3 节) val fragile_match_1 : fragile -> unit = <fun>
let fragile_match_2 = function | String "constant" -> () | _ -> ()
Warning 52 [fragile-literal-pattern]: 代码不应依赖于此构造函数参数的实际值。它们仅供信息参考,并且在将来版本中可能会更改。(请参阅手册第 13.5.3 节) val fragile_match_2 : fragile -> unit = <fun>
module Immediate: sig type t [@@immediate] val x: t ref end = struct type t = A | B let x = ref A end
module Int_or_int64 : sig type t [@@immediate64] val zero : t val one : t val add : t -> t -> t end = struct include Sys.Immediate64.Make(Int)(Int64) module type S = sig val zero : t val one : t val add : t -> t -> t end let impl : (module S) = match repr with | Immediate -> (module Int : S) | Non_immediate -> (module Int64 : S) include (val impl : S) end