2

我想做一个验证函数,取一个名字并输出一个validName类型。我不想在ValidName不使用函数的情况下在模块之外构造类型的值validateName

我试图将ValidName类型设为私有,但它使我无法在validateName函数中使用它(如果它在同一个模块中,则事件)。

在 rescript 中执行此操作的正确方法是什么?

这里是游乐场

这是代码:

module MyModule = {
    type notValidatedName = NotValidatedName(string)
    type validName = private ValidName(string)
    type errorMessage = string
  
    let validateName = (~name: notValidatedName): Belt.Result.t<validName, errorMessage> => {
      switch name {
      | NotValidatedName(name) when Js.String2.length(name) <= 2 => Belt.Result.Ok(ValidName(name)) // not possible because ValidName is private
      | _ => Belt.Result.Error("String is too short to be a name")
      }
    }
}

let nameToShort = MyModule.ValidName("aa")           // I don't want this to be possible
let notValidName = MyModule.NotValidatedName("aa")   // This is fine

let nameResult = MyModule.validateName(~name=notValidName)
4

1 回答 1

1

可见性是在模块签名中指定的(通常是类型注释),而不是定义本身。您也不需要构造函数,而是应该将类型设为抽象,或将类型别名设为私有。

您可以在本地模块上指定模块签名,如下所示,但通常您会将其放在.resi(“接口”)文件中。您可以放入模块签名中的所有内容也可以放入接口文件中。有关更多信息,请参阅文档

我会这样做:

module MyModule: {
  type validName = private string
  let validateName: string => result<string, string>
} = {
  type validName = string

  let validateName = name => {
    if String.length(name) <= 2 {
      Ok(name)
    } else {
      Error("String is too short to be a name")
    }
  }
}

let nameToShort: MyModule.validName = "aa" // Type error: is 'string', wanted 'MyModule.validName'
let notValidName: string = "aa" // This is fine

let nameResult = MyModule.validateName(notValidName)

switch nameResult {
  | Ok("aa") => Js.log("yay!")
  | Ok(_) => Js.log("wat?")
  | Error(err) => Js.log(err)
}

私有类型别名意味着该类型的值在任何方面都被视为 a string,除非您不能在定义它的模块之外构造或强制该类型的字符串。

如果您将其抽象化(通过替换type validName = private string为 just来实现type validName),则您将别名完全隐藏在外部世界之外。与这种类型的值交互的唯一方法是通过它公开的函数将它传递回模块。

于 2021-04-01T19:07:56.860 回答