Matlab 如何调用对象';当它的一个方法被用作其自身属性的回调时,是否使用它的析构函数?
我正在尝试编写一个类,该类围绕Matlab 如何调用对象';当它的一个方法被用作其自身属性的回调时,是否使用它的析构函数?,matlab,oop,Matlab,Oop,我正在尝试编写一个类,该类围绕串行端口来读取传感器: classdef sensor < handle properties Value s end methods function obj = sensor(port) obj.s = serial(port); obj.s.BytesAvailableFcn = @(o,e) obj.getData;
串行
端口来读取传感器:
classdef sensor < handle
properties
Value
s
end
methods
function obj = sensor(port)
obj.s = serial(port);
obj.s.BytesAvailableFcn = @(o,e) obj.getData;
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try
fclose(obj.s);
delete(obj.s);
end
end
function getData(obj)
obj.Value = fscanf(obj.s, '%d');
end
end
end
根据my,必须仍然有对foo
的引用。原来这是嵌入在串行端口中的foo.s
:
>> ports = instrfindall;
>> ports.BytesAvailableFcn
ans =
@(o,e)obj.getData
一旦我清除了字节AvailableFcn
,即
>> ports.BytesAvailableFcn = '';
然后清除所有
,我会显示名为析构函数的
如何打破这个循环引用并调用析构函数?如果没有调用析构函数,串行端口将保持绑定状态。问题不在于您有一个循环引用;从理论上讲,MATLAB应该能够捕捉到这些。问题是循环引用是通过Java实现的,而MATLAB无法捕获它
更详细地说,您的serial
对象内部包含一个Java对象,它是捕获到串行端口连接的真实对象。当您设置其回调时,MATLAB将设置底层Java对象的回调。如果回调是指向包含串行对象作为属性的对象的方法,那么就有一个通过底层Java对象的循环引用。当你调用clear
时,MATLAB会检查循环引用,如果它们都在MATLAB中,它会捕捉它们,并调用析构函数——但它不会捕捉它们,因为它是通过Java进行的
一种解决方案是显式调用析构函数,这可能不会太麻烦
另一个解决方法可能是不将回调作为类的方法—也许它只是一个常规函数,因为除了对串行对象的引用之外,它似乎并不真正需要来自主对象本身的任何信息。如果希望将所有代码保存在一个文件中,或许可以将其创建为一个匿名函数(尽管要小心,因为匿名函数将捕获创建它的工作区,这取决于创建它的位置,可能包括对主对象的引用,在这种情况下,您将再次使用循环引用)
编辑:Rody是对的-很抱歉,我读问题的速度太快了,没有注意到getData
实际上设置了值
属性,而不仅仅是返回数据。Rody在回答中的解决方案可能是另一种解决方法,但正如他所说的-是。我只需要手动调用delete
。有趣的问题!:)
我找到了一个解决办法,但不会很好
- 不能使用匿名函数。这将捕获本地工作区,其中将包含对
obj
的引用。您必须使用一个级别的间接寻址(到静态方法,否则,您将遇到相同的问题)李>
- 此静态方法可以安全地返回函数句柄。此函数句柄指向一个函数,该函数必须传递给instrument对象李>
- 如果不向对象传递引用,设置
Value
属性当然是不可能的,因此,必须在函数中创建全局状态、可变调用签名和Value
属性的getter李>
我有一种感觉,我设计得有点过头了(毕竟现在是星期五),所以如果有人看到更简单的方法,请纠正我。总之,我的意思是:
classdef sensor < handle
properties
s
end
properties (Dependent)
Value
end
methods
function obj = sensor(port)
obj.s = serial(port);
% You cannot use function handle without implicitly passing obj into
% it. Instead, get a function handle from another function, one that
% does not have this problem:
obj.s.BytesAvailableFcn = sensor.getGetData(obj.s);
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try %#ok<TRYNC>
fclose(obj.s);
delete(obj.s);
end
end
% Use a getter for Value, so that whenever you query the Value property,
% you get the most recently read sensor data
function V = get.Value(obj) %#ok<MANU>
V = getData();
end
end
% Use indirection to a Static method, to avoid referencing obj implicitly
methods (Access = private, Static)
function f = getGetData(S)
f = @(o,e)getData(S);
end
end
end
% The actual sensor reader
function data = getData(S)
persistent port
if nargin == 1
port = S; return; end
try
data = fscanf(port, '%d');
catch ME
% ...
end
end
classdef传感器
只是……恶心 显而易见的解决方案是显式调用delete
方法,但我希望有更好的方法。我不知道如何在不引用对象的情况下创建函数(不依赖于某些全局状态),如果您想让它设置值
属性…手动调用删除
将是我的首选。yeesh。干得好!事实上,这带来了一个很好的观点。如果我们使用instrfind('Type','serial','port',nameOfPort)
,并传递端口名(COM1等),而不是使用持久端口,该怎么办?然后在类构造函数中实例化一个“匿名”serial
对象。我必须考虑一下。这样你甚至不必把s
作为类的属性。我想知道这是否会有帮助…我猜一个持久的会有更好的表现。如果您经常阅读值
,则不希望每次都搜索所有端口…从面向对象的角度来看,让类管理串行端口是有意义的,换句话说,将其作为属性。但是如果MATLAB/Java接口有问题,而这是解决方法,那么也许你的想法是
classdef sensor < handle
properties
s
end
properties (Dependent)
Value
end
methods
function obj = sensor(port)
obj.s = serial(port);
% You cannot use function handle without implicitly passing obj into
% it. Instead, get a function handle from another function, one that
% does not have this problem:
obj.s.BytesAvailableFcn = sensor.getGetData(obj.s);
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try %#ok<TRYNC>
fclose(obj.s);
delete(obj.s);
end
end
% Use a getter for Value, so that whenever you query the Value property,
% you get the most recently read sensor data
function V = get.Value(obj) %#ok<MANU>
V = getData();
end
end
% Use indirection to a Static method, to avoid referencing obj implicitly
methods (Access = private, Static)
function f = getGetData(S)
f = @(o,e)getData(S);
end
end
end
% The actual sensor reader
function data = getData(S)
persistent port
if nargin == 1
port = S; return; end
try
data = fscanf(port, '%d');
catch ME
% ...
end
end