【问题标题】:F# Matching mutable object (string)F# 匹配可变对象(字符串)
【发布时间】:2010-09-16 03:27:29
【问题描述】:

这是目前为止的完整代码:

module clean
#light
open System
open System.IO
let pause() = Console.ReadLine()
let drive = System.IO.Directory.GetDirectoryRoot(System.IO.Directory.GetCurrentDirectory())
printfn "You're using the %s drive.\n\n" drive

let game1 = "Assassin's Creed"
let game2 = "Crysis"
let game3 = "Mass Effect"

let local1 = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\"
let local2 = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\"
let local3 = "\%USERPROFILE\%\\Documents\\BioWare\\Mass Effect\\Save\\"

let roam1 = drive + "Saves\\Abraxas\\" + game1 + "\\"
let roam2 = drive + "Saves\\Abraxas\\" + game2 + "\\"
let roam3 = drive + "Saves\\Abraxas\\" + game3 + "\\"




let rec getGame() =
  printfn "Which Game?\n\n   1.%s\n   2.%s\n   3.%s\n\n" game1 game2 game3
  match Int32.TryParse(stdin.ReadLine()) with
  | true,1 -> game1
  | true,2 -> game2
  | true,3 -> game3
  | _ ->
     printfn "You did not enter a valid choice."
     let _ = pause()
     Console.Clear()
     getGame()

let mutable gameprint = getGame()
printf "You have chosen %s\n\n" gameprint

let roaming =
  match gameprint with
  | game1 -> roam1
  | game2 -> roam2
  | game3 -> roam3
  | _ -> "test"

printf "Roaming set to %s\n\n" roaming

let local =
  match gameprint with
  | game1 -> local1
  | game2 -> local2
  | game3 -> local3
  | _ -> "test"

printf "Local set to %s\n\n" local

printf "Check gameprint  %s" gameprint

在设置漫游和本地对象的部分中,它告诉我它永远不会与“game1”以外的任何东西匹配。

我在匹配本地和漫游对象之前和之后执行了“printf”检查...游戏打印在两个 printf 命令中都正确显示,但与 game1 以外的任何内容都不匹配...我'我不确定我在哪里犯了错误。

【问题讨论】:

  • 这应该还是坚持DRY原则。我不会在任何地方重复任何字符串声明(我没有将 gamen 嵌入到 localn 中,因为在 localn 中发生变化的不仅仅是 gamen,不同的游戏很少有类似的结构,如您所见)。 DRY 原则的一部分:“逻辑上相关的元素都可预测且一致地变化”。如果要更改,Localn 永远不会发生可预测的更改。

标签: f# string-matching


【解决方案1】:

两件事。

  1. 在 F# 中,绑定可以被隐藏。特别是,在您的match 中,当您在模式中使用game1game2game3 时,您实际上是在用这些名称声明new 绑定。因此,第一个模式将始终匹配,并且只会在评估右侧之前将您尝试与之匹配的任何值分配给新绑定 game1

    解决此问题的一种方法是使用 [<Literal>] 属性声明您的 gameN 绑定(但请注意,它们也必须以大写字母开头才能用作常量):

    [<Literal>] let Game1 = "Assassin's Creed"

    现在您可以在模式匹配中使用Game1,它会按您的预期工作。

  2. 1234563 .

【讨论】:

  • 1.完美,感谢您的帮助! 2. 我稍后将在代码中对其进行更改,因此它需要是可变的。感谢您的检查。
【解决方案2】:

请参阅F# matching with two values 了解说明。

当与一些非文字值进行比较时,我只会使用 if-then-else

if gameprint = game1 then ...
elif gameprint = game2 then ...
...

【讨论】:

    【解决方案3】:

    也许更像这样的东西可以让您使其更具可扩展性(如果您在运行时填充游戏列表)......对不起,代码有点匆忙我正在努力准备工作:

    open System 
    type Game = {Title:string; local:string; roam:string}
    
    let game1 = {
        Title= "Assassin's Creed"; 
        local = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\"; 
        roam = "Saves\\Abraxas\\\Assassin's Creed\\"
    }
    let game2 = {
        Title= "Crysis"; 
        local = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\"; 
        roam = "Saves\\Abraxas\\\Crysis\\"
    }
    let games = [game1; game2]
    let printGamelListItem i g = printfn "%i: %s" i g.Title
    
    let printChoice() = 
        printfn "Which Game?\n"
        games |> List.fold (fun acc g -> 
                                printGamelListItem acc g 
                                acc+1) 1
        |> ignore
    
    let rec getGame() = 
        printChoice()
        match Int32.TryParse(Console.ReadLine()) with
        |true, x  when x <= games.Length -> games.[x-1]
        | _ ->
            printfn "You did not enter a valid choice."
            let _ = Console.ReadLine()
            Console.Clear()
            getGame()
    
    let selection = getGame()
    printfn "Roaming set to: %s" (selection.roam)
    printfn "Local set to: %s" (selection.local)
    

    【讨论】:

    • 感谢有趣的解释,我一定会在完成后回头看这个,但这比我在第 4 天准备的要复杂一些。我喜欢这个方向不过一目了然:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    相关资源
    最近更新 更多