可变值和不可变值重新定义有什么区别? [英] What is the difference between mutable values and immutable value redefinition?

查看:180
本文介绍了可变值和不可变值重新定义有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经读过F#中的值是不可变的。但是,我也遇到了重新定义价值定义的概念,这影响了以前的定义。这与可变值有什么不同?我问这不仅仅是一个理论上的结构,而且如果对何时使用可变值以及何时重新定义表达式有任何建议,或者如果有人可以指出后者不是惯用的f#。

重新定义的基本示例:

  let a = 1 ;; 
a ;; // 1
let a = 2 ;;
a ;; // 2

更新1:

除了下面的答案之外,顶级Fsharp交互中的重定义只允许在不同的终端中使用。以下将在fsi中抛出一个错误:

  let a = 1 
let a = 2 ;;

错误:重复定义值'a'

另一方面。,重新定义允许在let绑定



更新2:
实用性差,密封件不能与可变变量工作:

  let f = 
let mutable a = 1
let g()= a // error
0
f ;;

更新3:

尽管我可以例如:

  let f = 
let a = ref 1
let g = a
a:= 2
让x =!g +!a
printfnx:%ix // 4

f ;;

我不太清楚重新定义和使用mutable关键字的实际区别,例如:

  let f = 
let a = 1
let g = a
让a = 2
让x = g + a
printfnx:%ix // 3

f ;;

vs

  let mutable a = 1 
let g = a
a <-2
let x = g + a
printfnx: %ix // 3
f ;;

另一种思路:我不确定如何使用线程,但(a)可以另一个线程可以在let绑定中改变可变变量的值,(b)另一个线程可以在let绑定中重新绑定/重新定义一个值名称。



更新4:
最后一种情况的区别在于突变仍然会发生在嵌套范围内,而重新定义/重新嵌套在嵌套的作用域中会影响外部作用域的定义。

  let f = 
let mutable a = 1
let g = a
if true然后
a <-2
let x = g + a
printfnx:%ix // 3

f ;;

vs

  let f = 
let a = 1
let g = a
if true然后
let a = 2
printfna:%ia
let x = g + a
printfnx:%ix // 2
f ;;


解决方案

'我不确定我是否同意给出了答案。



以下内容在FSI和实际汇编中完美编译和执行:

 让TestShadowing()= 
让a = 1
让a = 2
a

但重要的是要了解发生的事情不是突变,而是阴影。换句话说,'a'的价值没有被重新分配。另一个'a'已经以其不变的价值被宣布。为什么区分很重要?考虑当'a'在内部块中被遮蔽时会发生什么:

 让TestShadowing2()= 
let a = 1
printfna:%ia
if true然后
让a = 2
printfna:%ia
printfna:%i a

> TestShadowing2();;
a:1
a:2
a:1

在这种情况下第二个'a'只影响第一个,而第二个在范围内。一旦它超出范围,第一个'a'就会恢复生效。



如果您没有意识到这一点,它可能会导致微妙的错误!



'p>的在盖伊编码器的评论的光澄清:



我上面描绘这一行为发生的重新定义时在一些让绑定(即在我的例子TestShadowing()函数内)。我想说的是迄今为止实践中最常见的情况。但正如盖伊所说,如果你重新定义在顶层,例如:

  module Demo = 

让a = 1
让a = 2

你确实会得到一个编译器错误。 / p>

I have read that values in F# are immutable. However, I have also come across the concept of redefining value definitions, which shadow the previous ones. How is this different from a mutable value ? I ask this not just as a theoretical construct, but also if there is any advice on when to use mutable values and when to redefine expressions instead; or if someone can point out that the latter is not idiomatic f#.

Basic example of redefinition:

let a = 1;;
a;; //1
let a = 2;;
a;; //2

Update 1:

Adding to the answers below, the redefinition in Fsharp interactive at top level is only allowed in different terminations. The following will throw up an error in fsi as well:

let a = 1
let a = 2;;

Error: Duplicate definition of value 'a'

On the other hand, redefinition is allowed in let bindings.

Update 2: Practical difference, closures cannot work with mutable variables:

let f =
   let mutable a = 1
   let g () = a //error
   0  
f;;

Update 3:

While I can model side effects with refs, eg:

let f =
   let  a = ref 1
   let g = a
   a:=2
   let x = !g  + !a
   printfn "x: %i" x //4

f;;

I can't quite see a practical difference between redefinition and using the mutable keyword, besides the difference in usage with closures, eg:

let f  =
   let a = 1
   let g  = a
   let a = 2
   let x = g + a
   printfn "x: %i" x //3

f;;

vs

let f =
   let mutable a = 1
   let g = a
   a <-2
   let x = g  + a
   printfn "x: %i" x //3
 f;;

Another line of thought: I'm not sure how to work with threads, but (a) can another thread can mutate the value of a mutable variable within a let binding and (b) can another thread rebind/redefine a value name within a let binding. I am certainly missing something here.

Update 4: The difference in the last case is that the mutation would still happen from a nested scope, whereas a redefinition/rebinding in the nested scope will 'shadow' definition from the external scope.

let f =
   let mutable a = 1
   let g = a
   if true then
      a <-2   
   let x = g  + a
   printfn "x: %i" x //3

f;;

vs

let f =
   let a = 1
   let g = a
   if true then
      let a = 2  
      printfn "a: %i" a   
   let x = g  + a
   printfn "x: %i" x //2
f;;

解决方案

'I'm not sure I agree with some of the answers given.

The following compiles and executes perfectly both in FSI and in a real assembly:

let TestShadowing() =
   let a = 1
   let a = 2
   a

But it's important to understand that what is going on is not mutation, but shadowing. In other words the value of 'a' hasn't been reassigned. Another 'a' has been declared with its own immutable value. Why does the distinction matter? Consider what happens when 'a' is shadowed in an inner block:

let TestShadowing2() =
   let a = 1
   printfn "a: %i" a
   if true then
      let a = 2
      printfn "a: %i" a
   printfn "a: %i" a

> TestShadowing2();;
a: 1
a: 2
a: 1

In this case the second 'a' only shadows the first one while the second one is in scope. Once it goes out of scope the first 'a' pops back into existence.

If you don't realize this it can lead to subtle bugs!

Clarification in the light of Guy Coder's comment:

The behaviour I decribe above occurs when the redefinition is within some let binding (i.e. within the TestShadowing() functions in my examples). This I would say is by far the most common scenario in practice. But as Guy says, if you redefine at the top level, e.g.:

module Demo =

   let a = 1
   let a = 2

you will indeed get a compiler error.

这篇关于可变值和不可变值重新定义有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆