我正在尝试创建一个接受字符串的方法,并尝试根据第二个参数将其解析为int或double。我的代码看起来正确,但给我一个类型不匹配。但看起来它们是正确的类型......
我希望获得有关如何修复它的建议。以下是我到目前为止的地方。
let double = Type.GetType("System.Double")
let int32 = Type.GetType("System.Int32")
let rec checkinput input (msType:Type)=
//force them to give you a good number
let ConsoleTrap parsed msType=
if fst parsed then
snd parsed //return the parsed value
else //the parse failed
Console.WriteLine "Enter a real number"
let newInput = Console.ReadLine()
checkinput newInput
//do it slightly differently based on whether we want an int or double
if msType = double then
ConsoleTrap (Double.TryParse input) (double)
else
ConsoleTrap (Int32.TryParse input) (int32)
答案 0 :(得分:1)
问题的第一部分是ConsoleTrap
内的递归调用缺少参数。您只需提供newInput
,但也需要msType
。您可以将该行更改为:
checkinput newInput msType
现在,这仍然没有用,但我们更接近了。现在的问题是,不清楚函数的结果应该是什么。在:
if msType = double then
ConsoleTrap (Double.TryParse input) (double)
else
ConsoleTrap (Int32.TryParse input) (int32)
... true
分支返回float
,false
分支返回int
。所以这是一个类型检查错误。您可以通过使函数checkinput
成为通用函数并仅处理int
和double
个案例(但使其返回'T
)来解决此问题。然后,您可以添加不安全的unbox
。以下内容适用:
let rec checkinput input : 'TResult =
//force them to give you a good number
let inline doer parsed : 'TLocal =
if fst parsed then
snd parsed //return the parsed value
else //the parse failed
Console.WriteLine "Enter a real number"
let newInput = Console.ReadLine()
unbox<'TLocal> (checkinput newInput)
//do it slightly differently based on whether we want an int or double
if typeof<'TResult> = double then
unbox<'TResult> (doer (Double.TryParse input))
else
unbox<'TResult> (doer (Int32.TryParse input))
那说,现在它变得有点难看,所以我可能不想使用这种代码。如果没有这个,你可能会有更多的重复,但如果有一些重复,你可以用一种更易读的方式解决原始问题。
答案 1 :(得分:1)
我决定试一试,结束了两种不同的事情 第一个依赖于“duck typing”。
let inline checkInput input =
let parsed = ref Unchecked.defaultof<_>
let rec aux input =
if (^a : (static member TryParse : string * ^a byref -> bool) (input, &parsed.contents)) then
!parsed
else
Console.WriteLine "Enter a real number"
aux (Console.ReadLine ())
aux input
// usage
let n = checkInput<int> (Console.ReadLine ())
// let n : int = checkInput (Console.ReadLine ()) // equivalent syntax
let d = checkInput<double> (Console.ReadLine ())
// works for any type with a matching TryParse member
let dt = checkInput<DateTime> (Console.ReadLine ())
第二个依赖于discriminated union。
type ParseType = IntType | DoubleType
type ParseResult = IntResult of int | DoubleResult of double
// (note "input" arg could be η-converted)
let checkInput pType input =
let rec aux parser resultCtor input =
match parser input with
true, parsed -> resultCtor parsed
| _ ->
Console.WriteLine "Enter a real number"
aux parser resultCtor (Console.ReadLine ())
// use the function associated with given "type case"
match pType with
IntType -> aux Int32.TryParse IntResult input
| DoubleType -> aux Double.TryParse DoubleResult input
// usage
let n = checkInput IntType (Console.ReadLine ())
let d = checkInput DoubleType (Console.ReadLine ())
答案 2 :(得分:0)
在查看Tomas回答后,我能够以不同的方式编译它,使用box然后取消框。
let double = Type.GetType("System.Double")
let int32 = Type.GetType("System.Int32")
//takes the user input and forces them to enter a valid number
// can return either valid doubles or ints
let rec checkinput (input) (msType:Type) =
//force them to give you a good number
let ConsoleTrap (parsed: obj) (msType :Type)=
let parsed = unbox parsed
if fst parsed then
snd parsed //return the parsed value
else
Console.WriteLine "Enter a real number"
let newInput = Console.ReadLine()
checkinput newInput msType
//do it slightly differently based on whether we want an int or double
if msType = double then
let parsed = Double.TryParse input
ConsoleTrap (box parsed) double
else
let parsed = Int32.TryParse input
ConsoleTrap (box parsed) int32