警告40的含义是什么:此记录...包含在当前范围内不可见的字段

lam*_*y.x 14 ocaml

请考虑以下代码:

module A =
  struct
    type r = { i : int; s: string }
  end

module B =
  struct
    type r = { i : int; s : string }
  end


let f (x : A.r) : B.r = match x with
    { i; s } -> { i = 2*i; s = "" }
Run Code Online (Sandbox Code Playgroud)

两个模块定义完全相同的记录.函数f将A记录转换为B记录.警告已在编译期间发出,但也可以交互显示.在ocaml cli上,似乎对f的调用完成了预期的事情:

# let x = f { i = 5; s = "ab" };;
Characters 10-29:
  let x = f { i = 5; s = "ab" };;
            ^^^^^^^^^^^^^^^^^^^
Warning 40: this record of type Shadow.A.r contains fields that are 
not visible in the current scope: i s.
They will not be selected if the type becomes unknown.
val x : Shadow.B.r = {Shadow.B.i = 10; s = ""}
Run Code Online (Sandbox Code Playgroud)

我在lexifi.com上发现了一篇博,解释了这个问题和一些常见的解决方案.我不明白的是实际的错误信息:

  • 什么类型变得未知是什么意思?
  • 未选择字段时的含义是什么?
  • 并由上述两个结果:需要满足哪些条件才能忽略警告?

gsg*_*gsg 15

在这种情况下,记录的类型是已知的,因为您提供了注释.如果删除了注释,则类型将变为未知,代码的含义可能会更改.

OCaml的哲学是添加和删除类型注释不应该影响程序的含义,因此会产生警告.

您可以通过将相关字段放入范围来避免此警告.对模块中定义的字段执行此操作A需要打开A以将其内容放入范围,或者使用模块限定字段名称.例如:

module A = struct ... end

let test r = r.A.field

let test2 r = let open A in r.field

open A 

let test3 r = r.field
Run Code Online (Sandbox Code Playgroud)

  • 只是为了澄清:我需要使用定义记录的模块,而不是具有字段类型的模块?(假设我有一个`模块C = struct type dummy = int end`并将Ai和Bi的类型更改为C.dummy,那么我仍然需要使用A和B,而不是C) (2认同)