zoukankan      html  css  js  c++  java
  • F#新Bug,小心! module 里的泛型变量。

            原则上,.Net不支持静态泛型变量,但是 F# 的语法支持,如:

            module Mithra =

                    let Empty<'T> = Seq.empty <'T>

           但是,这只是个语法糖而已。把这 F# 代码块编译成一个库,在C#里调用,即可看到,没有 Empty 变量,只有 Empty 函数。也就是说,这个“Empty”在 F# 里面,只是看起来像变量,实际上是在执行一个函数。

           这有什么关系呢?答:有关系。 
     
           参照老赵的《逆泛型执行器》,如果有泛型变量的话。F# 下,实现逆泛型是轻而易举的事。

        // 声明泛型函数变量

          let _getBytes<'T>  = ref Unchecked.defaultof< 'T->byte[] >

          // 泛型变量具现化,赋值

     

          _getBytes<int16> := BitConverter.GetBytes

          _getBytes<int32> := BitConverter.GetBytes

          _getBytes<int64> := BitConverter.GetBytes

          _getBytes<String> := Encoding.UTF8.GetBytes

          // 取出函数

     

          let GetBytes<'T> = !_getBytes<'T>  


            上面的代码,理论上已经实现了逆泛型,但是当调用 GetBytes 的时候,却发现 GetBytes 还是 null 值!原因何在?

            就是因为 _getBytes 不是变量,而是个函数。每次调用_getBytes,都会重新计算,返回一个 null 的引用值。因此上 F#中 module 里允许泛型变量,这不仅仅是个语法糖,还是个有毒的语法糖。使用的时候,必须先理解其实现实质,不然就会蹦出错误。


            下面,给出使用泛型类替代泛型变量后,正确的代码:

            module Mithra =

            type Cache<'T> () =

                static memberval GetBytes: 'T -> byte[] = Unchecked.defaultof< 'T ->byte[] > with get, set 

            Cache<int16>.GetBytes <- BitConverter.GetBytes

            Cache<int32>.GetBytes <- BitConverter.GetBytes

            Cache<int64>.GetBytes <- BitConverter.GetBytes

            Cache<String>.GetBytes <- Encoding.UTF8.GetBytes 

            let GetBytes<'T> = Cache<'T>.GetBytes

     






     





  • 相关阅读:
    《第三周作业》——第四小组
    《UML与设计原则》--第四小组
    《我与计算机》——第四小组
    PSP数据比较(四则运算)——计应193第6组栗亚文
    个人工作流程(地铁收费系统)——计应193第6组张淑雅
    设计模式学习总结
    行为型模式总结
    UML第二部分和创建型模式的总结(二)
    UML第二部分和创建型模式的总结
    UML第一部分和设计模式原则的总结
  • 原文地址:https://www.cnblogs.com/greatim/p/3943358.html
Copyright © 2011-2022 走看看