如何在 rescript 中将类型构造函数设为私有(当前模块除外)?
How to make a type constructor private in rescript (except in current module)?
我想创建一个验证函数,它取一个名字并输出一个 validName
类型。我不希望在不使用函数 validateName
.
的情况下在模块外部构造类型 ValidName
的值
我正在尝试将 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)
可见性是在模块签名中指定的(通常是类型注释),而不是定义本身。您也不需要构造函数,但应该将类型设为抽象类型或将类型别名设为私有。
您可以在本地模块上指定模块签名,如下所示,但通常您会将其放在 .resi
(“接口”)文件中。您可以放入模块签名中的所有内容也可以放入接口文件中。有关更多信息,请参阅 the docs。
我会这样做:
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)
}
私有类型别名意味着该类型的值在任何方面都被视为 string
,除了您不能在定义它的模块之外构造或强制该类型的字符串。
如果您将其抽象化,即通过将 type validName = private string
替换为 type validName
来实现,则您可以完全隐藏别名,不让外界看到。与这种类型的值交互的唯一方法是通过它公开的函数将它传回模块。
我想创建一个验证函数,它取一个名字并输出一个 validName
类型。我不希望在不使用函数 validateName
.
ValidName
的值
我正在尝试将 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)
可见性是在模块签名中指定的(通常是类型注释),而不是定义本身。您也不需要构造函数,但应该将类型设为抽象类型或将类型别名设为私有。
您可以在本地模块上指定模块签名,如下所示,但通常您会将其放在 .resi
(“接口”)文件中。您可以放入模块签名中的所有内容也可以放入接口文件中。有关更多信息,请参阅 the docs。
我会这样做:
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)
}
私有类型别名意味着该类型的值在任何方面都被视为 string
,除了您不能在定义它的模块之外构造或强制该类型的字符串。
如果您将其抽象化,即通过将 type validName = private string
替换为 type validName
来实现,则您可以完全隐藏别名,不让外界看到。与这种类型的值交互的唯一方法是通过它公开的函数将它传回模块。