如果我使用值SIDE_NO = 1
运行此代码,它可以正常工作,但是当我将其更改为任何其他值时,它会给我一个错误。发生了什么事?
没有足够的输入参数。
CubePiece中的错误(第15行) obj.posX = x;
主要错误(第21行) cubePieces(x,y)= piece;
SIDE_NO = 2;
PIECE_NO = 9;
cubeColors = zeros(SIDE_NO, PIECE_NO);
for s = 1: SIDE_NO
cimg = Snapshot();
simg = ScanFace(cimg);
cubeColors(s,:) = GetColours(simg);
end
for x = 1: SIDE_NO
for y = 1: PIECE_NO
piece = CubePiece(x,y,cubeColors(x,y));
cubePieces(x,y) = piece;
end
end
classdef CubePiece
properties
posX % 1, 2, 3
posY % 1, 2, 3
color % red, blue, orange, yellow, white, green
faceCode % R,L,U,D,F,B
faceNo % 1, 2, 3, 4, 5, 6
end
methods
function obj = CubePiece(x,y,col)
obj.posX = x;
obj.posY = y;
obj.color = col;
obj.faceNo = x;
obj.faceCode = obj.getFaceCode(x);
end
function code = getFaceCode(~,num)
if num == 1
code = 'R';
elseif num == 2
code = 'L';
elseif num == 3
code = 'U';
elseif num == 4
code = 'D';
elseif num == 5
code = 'F';
elseif num == 6
code = 'B';
end
end
end
end
答案 0 :(得分:3)
您发出的问题是,当您继续将数据附加到循环内的数组时(导致数组的大小增加)。 MATLAB需要尝试扩展数组以包含数据,同时确保数组保持矩形。
所以,让我们看看发生了什么。
当您使用x
在1处循环并且每次将y
递增1时。每次循环都会创建一个新的CubePiece
实例。然后你隐式地向cubePieces
添加一个新列以存储它。
cubePieces(x,y) = piece;
我强调隐含,因为你不能pre-allocate cubePieces
成为它的最终尺寸([SIDE_NO x PIECE_NO]
)。因此,如果我们在循环中粘贴以下语句,我们可以监视cubePieces
的大小。
disp(size(cubePieces));
在保持y
等于1的同时循环浏览x
值时,您会看到以下条目。
1 1
1 2
1 3
...
1 9
正如您所看到的那样,在我们达到9(PIECE_NO
)之前,列数会继续增加。
现在,当你到达x
= 2时,MATLAB不能再添加一个条目(就像它一直在做的那样),而是必须添加整行因为矩阵/数组不能是不规则形状。因此,如果我们观察disp
语句的输出,我们将再次获得。
2 9
2 9
...
2 9
如果您注意到,这次通过内循环不会改变大小。这是因为MATLAB填写了8" dummy"第一次通过循环时整行的值,因为它要求新行有9列,但它只知道第一行的值。
所以问题是,如果你没有设置它们,MATLAB如何填写整个行值?答案是(对于对象) MATLAB为完全填充新行所需的每个元素调用默认的contstructor(没有输入参数调用的构造函数)。这是因为数组的所有成员必须是相同的类型(忽略heterogeneous objects)。
因此,当您第一次分配到cubePieces(2,1)
时。 MATLAB 实际的作用是什么。
cubePieces(2,:) = [piece, CubePiece(), CubePiece(), CubePiece()...];
所以这些空洞的构造函数正在为您解决问题。在您的构造函数中,您不会检查以确保提供正确的输入,而是您只是开始尝试使用它们。这显然会导致输入参数不足的错误。
CubePiece()
没有足够的输入参数。
CubePiece中的错误(第13行)
obj.posX = x;
13 obj.posX = x;
你想要做的是优雅地处理contstructor没有输入参数的情况,并提供有效的"默认"宾语。
您可以通过返回而不指定任何属性(if nargin == 0; return; end
)来执行此操作。或者,如果您需要各种属性的默认值,则可以在类定义的properties
块中指定这些默认值。
classdef CubePice
properties
posX = 1
posY = 1
color = 'red';
faceCode = 'R';
faceNo = 1
end
methods
function obj = CubePiece(x,y,col)
if nargin == 0
return;
end
obj.posX = x;
% Do other assignments
end
end
end
更好的解决方案是实际预先分配您要分配的变量,以便MATLAB不会不断改变它的大小。这有一些性能优势。有几种方法可以做到这一点
<强> repmat
强>
如果您确实需要CubePiece
个对象的2D数组,您实际上可以预先分配CubePiece
个对象的2D数组,使其大小合适。您可以使用repmat
应用于您的班级的单个实例来执行此操作。
template = CubePiece(1,1,1);
cubePieces = repmat(template, [SIDE_NO, PIECE_NO]);
现在您将拥有一个2D对象数组(技术上是相同对象的所有句柄),MATLAB不必对此数组进行任何动态扩展,并尝试猜测默认值你想要使用的价值。
&#34;展开一次&#34;方法强>
如果您不介意MATLAB调用默认构造函数(并且您已经设置了类构造函数来处理此问题),那么可以通过简单地分配值来来初始化此数组。首先是最大的行和列,它会立即将数组扩展到最大大小。
cubePieces(SIDE_NO, PIECE_NO) = CubePiece(1,1,1);
size(cubePieces)
2 9
单元格数组
您还可以在创建过程中将对象存储在单元格数组中。
cubePieces = cell(SIDE_NO, PIECE_NO);
for x = 1:size(cubePieces, 1)
for y = 1:size(cubePieces, 2)
cubePieces{x,y} = CubePiece(x, y, cubeColors(x,y))
end
end
然后如果需要,可以使用cell2mat
将单元格转换为2D数组。
现在这篇文章一直在谈论自定义MATLAB类;但是,这也适用于所有 MATLAB内置类。
以double
s。
x = 1:5
1 2 3 4 5
现在让我们在x(2,1)
添加一个元素。
x(2,1) = 6
1 2 3 4 5
6 0 0 0 0
显然,double
的默认值为0,因为MATLAB用0填充所有未指定的值。
我们可以对单元格数组执行相同操作,其中默认值为空数组([]
)。
y = num2cell(1:5)
[1] [2] [3] [4] [5]
y{2,1} = 6;
[1] [2] [3] [4] [5]
[6] [] [] [] []
有关此行为的更多信息,请访问this page。
当您动态扩展二维对象数组(无论它们是内置数据类型还是自定义类)时,MATLAB必须填充缺失值以保持矩形形状。 &#34;默认&#34;用于填充未指定值的值取决于数据类型。对于自定义类,此&#34;默认&#34;通过不带参数调用构造函数来创建数据类型。通过显式预分配多维数组,可以避免此默认行为。
答案 1 :(得分:0)
与Suever的答案没有达到同样精彩的细节水平,我只想为问题本身添加一些实用的解决方案。
正如Suever所说,问题是由于您正在添加Matlab尝试使用该类型的“默认”值填充的整行对象。这个难题有四种替代解决方案,但前两种已在另一个答案中提出:
repmat
的答案)。使用可以无限增长的一维数组,然后reshape
将其设置为正确的形状。但是,对于大型数组和非句柄类型,这可能会很慢,特别是由于不断重新分配。
for x = 1: SIDE_NO
for y = 1: PIECE_NO
i = sub2ind([SIDE_NO, PIECE_NO], x, y);
piece = CubePiece(x,y,cubeColors(x,y));
cubePieces(i) = piece; % Grow one by one
end
end
cubePieces = reshape(cubePieces, [SIDE_NO, PIECE_NO]);
使用单元格数组而不是类矩阵。您甚至可以将其预分配到正确的大小,因为默认值是空矩阵。完成后,您可以按原样使用它,或者使用cell2mat将其转换为正确的类型数组。
cubePieces = cell(SIDE_NO, PIECE_NO);
for x = 1: SIDE_NO
for y = 1: PIECE_NO
piece = CubePiece(x,y,cubeColors(x,y));
cubePieces{x,y} = piece;
end
end
cubePieces = cell2mat(cubePieces); % Or use as-is