英文:
byref typed value cannot be used at this point
问题
以下是翻译好的部分:
让我们假设我们实现了一个来自C#库的接口,其中涉及模拟多个返回值,而这个接口在极度简化后可能如下所示:
type IExternalCommand =
abstract Execute : byref<string> -> bool
让我们进一步假设,我们用以下表达式模拟了实际外部命令的奇怪工作方式:
type MyResult = Ok | Error of string
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module MyResult =
let toMyResult (message : byref<string>) = function
| Ok -> true
| Error msg -> message <- msg; false
let ok = { new IExternalCommand with
member __.Execute(message) =
MyResult.toMyResult &message Ok } // works
let error = { new IExternalCommand with
member __.Execute(message) =
MyResult.toMyResult &message <| Error "fail" }
// ^^^^^^^ FS0418 The byref typed value 'message' cannot be used at this point
我知道[F#规范][1]中有关Byref安全分析的部分,但我不明白这在这种情况下如何适用(除了byref值不能在对象表达式的成员实现中使用之外,这一点令人困惑)。此外,它曾经在F# 3中工作。为什么会这样?
[1]: https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf
<details>
<summary>英文:</summary>
Let's say we implement an interface from a C# library which involves simulation of multiple return values and which, starkly simplified, might look like this:
type IExternalCommand =
abstract Execute : byref<string> -> bool
Let's say further that we fake the strange workings of an actual external command with the following expressions:
type MyResult = Ok | Error of string
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module MyResult =
let toMyResult (message : byref<string>) = function
| Ok -> true
| Error msg -> message <- msg; false
let ok = { new IExternalCommand with
member __.Execute(message) =
MyResult.toMyResult &message Ok } // works
let error = { new IExternalCommand with
member __.Execute(message) =
MyResult.toMyResult &message <| Error "fail" }
// ^^^^^^^ FS0418 The byref typed value 'message' cannot be used at this point
I am aware of the section on Byref Safety Analysis in the [F# spec][1] but fail to see how this is applicable in this situation (except for the byref values may not be used in the member implementation of object expressions part, which is confusing). Also, it used to work in F# 3. Why is this?
[1]: https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf
</details>
# 答案1
**得分**: 3
这是因为`byref`类型不能用作类型参数 - 例如,像`List<byref<int>>`这样的东西是被禁止的。
当您尝试像这样调用函数时,从技术上讲,`MyResult.toMyResult`被视为类型为`FSarpFunc<byref<sting>, ...>`的表达式,然后将一个参数应用于它,然后将结果传递给`<|`操作符。类型为`FSarpFunc<byref<sting>, ...>`的值无法存在,因此会出现错误。诚然,错误消息可以更清晰一些。
在第一个示例中,这是有效的,因为F#对函数应用于其声明中恰好与参数一样多的情况有一个特殊情况。这种特殊情况在与非F#代码互操作时是必要的 - 其中包括处理这种特定情况。
就个人而言,我建议尽量不使用可变单元,它们是错误的主要来源。但如果您绝对需要可变单元,有两个选项。
选项1 - 不使用运算符来分解函数应用程序:
MyResult.toMyResult &message (Error "fail")
选项2 - 使用`ref<'t>`代替:
let tmp = ref ""
MyResult.toMyResult tmp <| Error "fail"
message <- !tmp
<details>
<summary>英文:</summary>
This is because a `byref` type cannot be used as a type parameter - e.g. something like `List<byref<int>>` is prohibited.
When you try to call the function like this, technically `MyResult.toMyResult` is treated as an expression of type `FSarpFunc<byref<sting>, ...>`, to which you then apply one parameter, and then pass the result of that to the `<|` operator. A value of type `FSarpFunc<byref<sting>, ...>` cannot exist, so you get an error. Admittedly, the error message could be clearer.
In the first example this works because F# has a special case for when a function is applied to exactly as many parameters as there are in its declaration. This special case is kind of necessary for interacting with non-F# code - among other things, to deal with this particular case.
Personally I would recommend not to use mutable cells if at all possible, they're a prime source of fat, juicy bugs. But if you absolutely must have a mutable cell, you have two options.
Option 1 - don't use an operator to break up function application:
MyResult.toMyResult &message (Error "fail")
Option 2 - use `ref<'t>` instead:
let tmp = ref ""
MyResult.toMyResult tmp <| Error "fail"
message <- !tmp
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论