• F#: mutable 关键字不适宜用于结构中声明可变值


     关于之前日志F#编译器的一个Bug》,有一个问题,Set函数既然运行正常,改变的值去哪里了?以下例子做出了解答:
     
    [<Struct>]
    type TestStruct =
    
        val mutable X: int
    
        new(x) = {_x = x}
    
        member this.Set(x) =
    
            this._x <- x
    
            this
     
    
    let a = TestStruct(2)
    
    let c() =
    
        let b = a.Set 10
    
        b.X
    
    c();;

     
    代码运行结果为10(我们想要的结果)。众所周知,类的子函数,其背后的实现是一个带对象输入的公共函数,调用a.Set(x),等效于执行伪代码:

    Set(a, x) 。

    由此可见,当我们绑定 
    let a = TestStruct(2),调用a.Set(x) 的时候,传递到Set函数中的this,其实是个复制值。
    而当
    我们绑定 let mutable a = TestStruct(2),调用a.Set(x) 的时候,传递到Set函数中的this,却是a本身。

     
    虽然,当我们在结构中使用
    mutable 的时候,可以使用返回this的方式,返回一个新的结构值。这也很符合函数编程的规范。但是如果可变数值使
    用的是引用单元格,而不是
    mutable 的话。表现又略微不同:

     
    mutable 方式,a值和Set返回值不同,一个表示原始值,另一个表示修改后的值;

    引用单元格方式,a就是修改后的值。

    [<Struct>]
    
    type TestStruct =
    
        val _x: int ref
    
        new(x) = {_x = ref x}
    
        member this.Set(x) =
    
            this._x := x
    
    member this.X = !this._x; 
    
    
    let a = TestStruct(2)
    
    let c() =
    
        a.Set 10
    
        a.X
    
     
    
    c();;


    以上这段代码,可以得到正确值10,原理很简单,int ref实际上是一个类,所以结构复制后,其对应的对象都是同一个。 
     

    所以用户仍然无法从习惯风格本身理解 
    TestStruct.Set(x)函数的行为。此外.Net库里面常用的一个StringBiulder类,它的行为特征,则完全符合引用单元格方式。所以结构中,mutable 的使用要尤其审慎。毕竟,一个结构,如果let绑定使用和let mutable绑定使用,两者之间行为不一致的话,利用这种特性写出的代码,未免太奇淫技巧一点,徒增读代码的难度。


  • 相关阅读:
    每日一练leetcode
    每日一练leetcode
    每日一练leetcode
    springboot搭建过程
    每日一练leetcode
    每日一练leetcode
    每日一练leetcode
    安装 Redis 迎客
    windows系统上面如何后台执行程序 迎客
    jira的详细安装和破解 迎客
  • 原文地址:https://www.cnblogs.com/greatim/p/3917991.html
Copyright © 2020-2023  润新知