Why can struct change their own fields?

前端 未结 5 1382
终归单人心
终归单人心 2020-12-03 16:11

Consider the Foo struct as follows:

struct Foo
{
  public float X;
  public float Y;

  public Foo(float x, float y)
  {
    this.X = x;
    this.Y = y;
  }
         


        
5条回答
  •  遥遥无期
    2020-12-03 16:39

    Since one cannot do

    Foo bar = new Foo(1, 2); 
    bar.X = 5; 
    

    Why can one use:

    Foo bar = new Foo(1, 2); 
    bar.Change(5); 
    

    Your original question actually cannot be answered because it is predicated on a completely false assumption. Both code samples are perfectly legal, and so the question about why one is illegal is nonsensical. Let's move on to your follow-up question:

    If structs are mutable, then why can't they be modified when in a list or returned from a property?

    Because variables are mutable and values are immutable.

    That's why they're called "variables", after all, because they can change.

    When you say "bar.X = 5", "bar" is a local variable. Variables are allowed to change.

    When you say "bar.Change(5)", "bar" is a local variable. Variables are allowed to change.

    When you say "myArray[123].X = 5", "myArray[123]" is an array element and an array element is a variable. Variables are allowed to change.

    When you say "myDictionary[123].X = 5", "myDictionary[123]" is not a variable. The value is returned from the dictionary, not a reference to the storage location. Since that is a value, not a variable, there is nothing there that can change, so the compiler does not allow it to change.

    A subtle point is that when you attempt to change a field, the receiver must be a variable. If it is not a variable, it makes no sense; you are clearly attempting to mutate a variable and there's nothing there to mutate. When you call a method, the receiver must be a variable but what if you have a value? The method might not attempt to mutate anything, and so should be allowed to succeed. What the compiler actually does if the receiver of a method call on a struct is not a variable, then it makes a new temporary local variable and calls the method with that variable. So if you say: "myDictionary[123].Change(5);" that is the same as saying

    var temp = myDictionary[123];
    temp.Change(5);
    

    Here "temp" is a variable, and the mutating method is allowed to change the temporary copy.

    Is that now clear? The key takeaway here is variables can change.

提交回复
热议问题