在下面的F#代码中,f1将跨度作为输入,f2调用f1.

let f1 (span: Span<byte>) = span.Length

let f2() =
    let buf = [|0uy|].AsSpan()
    buf |> f1 // FS0412
    f1 buf // Ok

FS0412 A type instantiation involves a byref type. This is not permitted by the rules of Common IL

有没有办法把一个跨距变成F#函数?

推荐答案

只需在why码的基础上增加一点 colored颜色 :

byref和类似byref的类型与函数优先编程背道而驰.

这些类型的整个生命周期都需要在堆栈上,并附带一些编译器分析,允许运行时省略一些判断.这对性能很好.

当一个函数成为一级函数时,它涉及到堆分配.基本上,这是一个有Invoke个方法的对象.在F#编译器中,有几种优化try 将F#函数转换为静态方法(大多数F#函数声明都是这样的),但在许多情况下,它们会作为堆上的对象发出(有些可以预测,有些不能).这意味着几件事:

  • 不能传递以byref或类似byref的类型作为参数的函数
  • 不能在lambda中使用byref或类似byref的类型
  • 不能在内部函数中使用byref或类似byref的类型

在某些情况下,这在技术上是可能的,但在源代码中没有任何内容可以说明为什么在某些情况下是可能的,而在其他情况下则不是.原因很简单,"因为编译器需要将此函数作为对象发出",这是完全不可预测和不一致的.proposed suggestion可能会有所帮助,但它的关闭有利于在编译器中进行调整,比如this suggestion,从可预测性的Angular 来看,这可能不会太糟糕.

现在,|>的情况更有趣了,声明为inline的其他几个函数也是如此.|>运算符的字面定义是将高阶函数作为参数,因此自然不应支持它.但因为它被定义为inline,它实际上可以工作,因为它只是一个优化.然而,这也可能要求您只能在other inline函数的上下文中使用它.您可能无法通过管道连接到任何任意函数.

这就是为什么这不是一个bug,而是一个副设计行为,如果它被实现的话,它会认真考虑增强:https://github.com/fsharp/fslang-suggestions/issues/688

.net相关问答推荐

ASP.NET核心最小API必须以正斜杠开头吗?

无法在Ubuntu 22.04.3上运行带有Rider 2023和DotNet-8.0的项目

从窗体中移除另一个控件中引用的控件时获取设计时通知

如果只有一个 : 存在于字符串中,则提取冒号后的内容

使用 SSH.NET 查找具有特定文件名的最新 SFTP 文件

问:在 Blazor WASM 应用程序中存储 api 密钥的最佳方式是什么?

如何在选项卡中 Select Winforms NumericUpDown 中的所有文本?

从 byte[] 创建 zip 文件

如何以编程方式判断类型是 struct 还是类?

使用 .NET 在 Windows 中创建弹出式 toastr 通知

将 Topshelf 应用程序安装为 Windows 服务

运算符重载 ==, !=, Equals

支持 HTTPS 的 Httplistener

如何使用反射在 .NET 中调用重载方法

何时使用抽象类?

如何在 C# 中安全地将 System.Object 转换为bool?

有没有办法从方法返回匿名类型?

log4net的正确使用方法(记录器命名)

接口属性的 XML 序列化

C# 应用程序中的全局键盘捕获