type foo = A of int * int | B of (int * int)
int * int
和(int * int)
之间有什么区别?我看到的唯一区别是模式匹配:
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
它只是一种语法糖吗?你如何选择使用哪一个?这两种形式之间是否有任何性能差异?
答案 0 :(得分:7)
是的,存在性能差异:
在内存中A (23, 42)
将包含一个标记为A
的标记,以及两个整数23和42. B (23, 42)
将包含一个标记为B
的标记,指向包含整数23
和42
的元组的指针。因此,在访问B
内的单个值时,在创建B
和一个额外的间接级别时,将会有一个额外的内存分配。因此,如果您实际上没有将构造函数参数用作元组,则使用A
将比使用B
所需的开销更少。
另一方面,每次使用test_foo
值调用时,A
函数都会创建一个新元组,但是当使用B
值调用它时,它将只返回已经存在于内存中的元组。因此test_foo
对B
的操作比对A
更便宜。B
。因此,如果您将构造函数的参数用作元组,并且您将对同一值使用多次,则使用{{1}}会更便宜。
因此,如果您要将构造函数参数用作元组,那么使用构造函数获取元组是有意义的,因为您可以使用较少代码的模式匹配来获取元组,因为它将避免必须创建多次来自相同值的元组。在所有其他情况下,不使用元组是更可取的,因为它涉及更少的内存分配和更少的间接。
答案 1 :(得分:2)
如上所述,A
的构造函数需要两个int
,而B
的构造函数需要一对有序的。
所以你可以写
let bar = A (1, 2)
或
let bar = B (1, 2)
或
let bar = (1, 2)
let baz = B bar
但你不能写
let bar = (1, 2)
let baz = A bar
此外,在模式匹配中,您仍然可以将B的内容与两个int匹配,但是您无法将A的内容与绑定到有序对的值匹配
let test_foo = function
| A a -> a (* wrong *)
| B (f, s) -> (f, s) (* ok *)
答案 2 :(得分:0)
它们是两种不同的类型。 *
运算符对此语法的解释不明确。它可以简化为:
type x = Y * Z
其中'*'与OCaml中的type
关键字相关联
要么
int * int
其中*
用于构造元组的运算符的容量
默认优先级将其带到前者。通过在(int * int)
周围加上一个括号,可以覆盖默认的优先级,并强制执行后一种解释。
答案 3 :(得分:0)
这是OCaml语法中的一个棘手问题 - 尽管看起来你正在声明一个带有元组数据类型(A of int * int
)的构造函数,即使你使用构造函数,它看起来像你给它一个元组(A (2,3)
),实际上并不是发生了什么。
如果您实际构造了一个元组值并尝试将其传递给构造函数,那么它将无法编译 - let x = (2,3) in A x
。相反,构造函数定义中的*
和构造函数使用表达式中的(,)
只是多个参数的构造函数的语法。语法模仿带有元组参数的构造函数,但实际上是分开的。如果你想用一个元组参数实际构造一个构造函数,那么额外的括号是必要的。