在下面的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相关问答推荐

使用EFCore.BulkExtensions库方法BulkInertOrUpdate时区分插入和更新的记录

Azure管道-使用.NET 8 RC2 SDK生成C#项目失败

F#:跨度、提升和底部类型(或缺乏)

dotnet ef dbcontext scaffold command --data-annotations 或 -d 命令行参数似乎不起作用

单击关闭按钮时隐藏表单而不是关闭

来自奥尔森时区的 .NET TimeZoneInfo

如何将浮点数向上舍入到 C# 中最近的 int?

有什么方法可以在不重新编译的情况下覆盖 .NET Windows 服务名称?

如何在 C# 中序列化异常对象?

静态析构函数

为什么 System.Timers.Timer 能在 GC 中存活,而 System.Threading.Timer 不能?

react 式扩展使用的好例子

C#中的T是什么意思?

如何将 WebResponse.GetResponseStream 返回转换为字符串?

是否可以完全用托管的 .NET 语言编写 JIT 编译器(本地代码)

我应该绑定到 ICollectionView 还是 ObservableCollection

从流中获取 TextReader?

使用 lambda 表达式代替 IComparer 参数

obj 文件夹是为了什么而生成的?

从 bcp 客户端接收到 colid 6 的无效列长度