为什么有些 FAKE 方法在目标函数中不起作用?
Why Is It That Some FAKE Methods Don't Work Within Target Functions?
考虑以下几点:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Shell.Exec("mkdir","exampleDirectory")
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
上面的脚本工作正常,但是当我像这样在目标中移动 Shell.Exec 时:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory")
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
我遇到了一个错误:
FsiEvaluationException:
Error:
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
unit
but here has type
int
Output: [Loading C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx]
Input: C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx
\Arguments:
C:\fsi.exe
Exception: Yaaf.FSharp.Scripting.FsiEvaluationException: Error while compiling or executing fsharp snippet. ---> System.Exception: Operation failed. The error text has been print the error stream. To return the corresponding FSharpErrorInfo use the EvalInteractionNonThrowing, EvalScriptNonThrowing or EvalExpressionNonThrowing
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.commitResult[a,b](FSharpChoice`2 res)
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.EvalScript(String filePath)
at Yaaf.FSharp.Scripting.Helper.evalScript@1303.Invoke(String arg00) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1303
at Yaaf.FSharp.Scripting.Helper.save_@1276-2.Invoke(Unit unitVar0) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1277
at Yaaf.FSharp.Scripting.Helper.consoleCapture[a](TextWriter out, TextWriter err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1221
at Yaaf.FSharp.Scripting.Helper.redirectOut@1247[a](Boolean preventStdOut, OutStreamHelper out, OutStreamHelper err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1254
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1276
--- End of inner exception stack trace ---
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1284
at Yaaf.FSharp.Scripting.Helper.session@1306.Yaaf-FSharp-Scripting-IFsiSession-EvalScriptWithOutput(String ) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1308
at Fake.FSIHelper.runScriptUncached(Boolean useCache, String scriptPath, IEnumerable`1 fsiOptions, Boolean printDetails, CacheInfo cacheInfo, TextWriter out, TextWriter err) in C:\code\fake\src\app\FakeLib\FSIHelper.fs:line 471
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
这里的重点是我试图仅在特定目标下执行 shell 命令。不要注意 mkdir 命令,因为我实际上想使用 schtasks 命令。为了简单起见,我只是使用 mkdir。也许我在这里遗漏了细微差别。我还注意到使用 environVarOrFail 时有同样的行为。预先感谢所有回复的人。
Shell.Exec
returns 一个 int
,但是 Target
期望一个 returns 一个 unit
.
的函数
试试这个:
let returnUnit() = ()
let return42() = 42
Target "One" returnUnit // works
Target "Two" return42 // fails: expected to have type unit, but here has type int
目标 "Two" 编译失败,因为它的第二个参数是 return 一个 int
的函数,而一个 returning [=16= 的函数] 预计。
这个错误是为了防止你忘记函数 return 的值:编译器会告诉你 "Hey, are you sure you don't want to do anything with this int? Then why did you call the function in the first place?"
然而,有时丢弃 return 值是有意义的。例如,在这种特殊情况下,您调用 Shell.Exec
是为了它的副作用,而您对它的 return 值不感兴趣。这种情况出奇地经常发生,以至于有一个特殊的功能来应对它 - ignore
.
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory") |> ignore // compiles fine
)
这个函数取任何值,把它扔掉,return是一个单位。通过将它应用于 Shell.Exec
的结果,您告诉编译器:"Yes, I'm sure I don't need this value, please ignore
it."
也就是说,我强烈建议使用专用函数而不是通用系统调用。这将使您的脚本更具可读性,甚至可以帮助您尽早发现偶尔出现的错误。例如,要创建目录,请使用 FileUtils.mkdir
:
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
FileUtils.mkdir "exampleDirectory" // no need for `ignore`, mkdir already returns `unit`
)
考虑以下几点:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Shell.Exec("mkdir","exampleDirectory")
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
上面的脚本工作正常,但是当我像这样在目标中移动 Shell.Exec 时:
#r @"FakeLib.dll"
open Fake
open Fake.StringHelper
open Fake.ProcessHelper
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory")
)
Target "Clean" ( fun () ->
trace "Cleaning..."
)
Target "Deploy" (fun () ->
trace "Deploying..."
)
"DoStuff"
==>"Clean"
==>"Deploy"
RunTargetOrDefault "Deploy"
我遇到了一个错误:
FsiEvaluationException:
Error:
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
unit
but here has type
int
Output: [Loading C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx]
Input: C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx
\Arguments:
C:\fsi.exe
Exception: Yaaf.FSharp.Scripting.FsiEvaluationException: Error while compiling or executing fsharp snippet. ---> System.Exception: Operation failed. The error text has been print the error stream. To return the corresponding FSharpErrorInfo use the EvalInteractionNonThrowing, EvalScriptNonThrowing or EvalExpressionNonThrowing
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.commitResult[a,b](FSharpChoice`2 res)
at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.EvalScript(String filePath)
at Yaaf.FSharp.Scripting.Helper.evalScript@1303.Invoke(String arg00) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1303
at Yaaf.FSharp.Scripting.Helper.save_@1276-2.Invoke(Unit unitVar0) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1277
at Yaaf.FSharp.Scripting.Helper.consoleCapture[a](TextWriter out, TextWriter err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1221
at Yaaf.FSharp.Scripting.Helper.redirectOut@1247[a](Boolean preventStdOut, OutStreamHelper out, OutStreamHelper err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1254
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1276
--- End of inner exception stack trace ---
at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1284
at Yaaf.FSharp.Scripting.Helper.session@1306.Yaaf-FSharp-Scripting-IFsiSession-EvalScriptWithOutput(String ) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1308
at Fake.FSIHelper.runScriptUncached(Boolean useCache, String scriptPath, IEnumerable`1 fsiOptions, Boolean printDetails, CacheInfo cacheInfo, TextWriter out, TextWriter err) in C:\code\fake\src\app\FakeLib\FSIHelper.fs:line 471
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
这里的重点是我试图仅在特定目标下执行 shell 命令。不要注意 mkdir 命令,因为我实际上想使用 schtasks 命令。为了简单起见,我只是使用 mkdir。也许我在这里遗漏了细微差别。我还注意到使用 environVarOrFail 时有同样的行为。预先感谢所有回复的人。
Shell.Exec
returns 一个 int
,但是 Target
期望一个 returns 一个 unit
.
试试这个:
let returnUnit() = ()
let return42() = 42
Target "One" returnUnit // works
Target "Two" return42 // fails: expected to have type unit, but here has type int
目标 "Two" 编译失败,因为它的第二个参数是 return 一个 int
的函数,而一个 returning [=16= 的函数] 预计。
这个错误是为了防止你忘记函数 return 的值:编译器会告诉你 "Hey, are you sure you don't want to do anything with this int? Then why did you call the function in the first place?"
然而,有时丢弃 return 值是有意义的。例如,在这种特殊情况下,您调用 Shell.Exec
是为了它的副作用,而您对它的 return 值不感兴趣。这种情况出奇地经常发生,以至于有一个特殊的功能来应对它 - ignore
.
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
Shell.Exec("mkdir","exampleDirectory") |> ignore // compiles fine
)
这个函数取任何值,把它扔掉,return是一个单位。通过将它应用于 Shell.Exec
的结果,您告诉编译器:"Yes, I'm sure I don't need this value, please ignore
it."
也就是说,我强烈建议使用专用函数而不是通用系统调用。这将使您的脚本更具可读性,甚至可以帮助您尽早发现偶尔出现的错误。例如,要创建目录,请使用 FileUtils.mkdir
:
Target "DoStuff" ( fun () ->
trace "Doing Stuff..."
FileUtils.mkdir "exampleDirectory" // no need for `ignore`, mkdir already returns `unit`
)