【发布时间】:2021-11-27 09:13:31
【问题描述】:
由于数组参数是不带引用关键字传递的,所以这段代码输出数组的初始值(即1...6):
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var arr = new int[] {1, 2, 3, 4, 5, 6};
Rotate(arr, 3);
Console.WriteLine(string.Join(',', arr));
}
static void Rotate(int[] nums, int k)
{
var tail = nums.TakeLast(k).ToArray();
nums = tail.Concat(nums)
.Take(nums.Length)
.ToArray();
}
}
很明显,因为在 Rotate 方法内部有它自己的值数组,从参数值复制而来。如果我想改变调用方法中的 arr 值,我需要通过 ref 将它传递给 Rotate 方法,它可以工作。 但我不明白,为什么如果用 CopyTo() 方法替换赋值,参数的行为就像是通过引用传递:
static void Rotate(int[] nums, int k)
{
var tail = nums.TakeLast(k).ToArray();
tail.Concat(nums)
.Take(nums.Length)
.ToArray()
.CopyTo(nums, 0);
}
【问题讨论】:
-
数组是 reference types 因此,当您将一个传递给方法时,将传递一个 reference 到数组的副本(引用本身是按值传递)。因此,方法内的数组
nums与传递给方法的引用具有相同的引用。它们是同一个数组。 -
我明白了,但是为什么第一个代码示例输出 1...6 呢?如果我在旋转末尾添加
Console.WriteLine(string.Join(',', nums));,它会打印'4,5,6,1,2,3'?此外,为什么添加 ref 也会导致 '4,5,6,1,2,3' 输出? -
它是自己的带有值的数组,从参数值复制 - 但您确实知道“复制”发生在调用 ToArray 的位置,而不是在调用方法的要点是什么?在 Rotate 的第一行(概念上为
{),甚至在TakeLast(k)执行之前,nums作为对arr引用的同一内存数组的替代变量引用。此后不久,nums被指向内存中其他位置(在第一个代码块中)的某个新数组,然后在方法结束时立即丢弃该数组