如何按需加载属性?
Posted
技术标签:
【中文标题】如何按需加载属性?【英文标题】:How to load a property on demand? 【发布时间】:2018-07-16 15:44:35 【问题描述】:我想按需加载一个属性,但我无法让它工作。
我有一个具有瞬态属性foo
的类。因此,保存对象时不会存储属性。当我使用调用属性 'foo' 的方法时,我希望 foo 的值从单独的 mat 文件加载并存储到对象中,只要它在工作区中。
我尝试了一些 get 和 set 方法,但无法正常工作。这可能吗?还是我总是添加一行代码来加载属性?下面的代码没有做我想要的,但它给出了我尝试的指示。
此外,下面的代码在使用该属性时会不断加载 foo.mat 文件。我只想加载一次 foo.mat 并将其存储为属性并从那里检索数据而不是加载。我的问题的原因是 foo 属性相当大,即一个本身具有许多属性的类。我只想在需要时加载它,不想将它存储在 foobar 类本身中。
classdef foobar
properties(Transient = true)
foo
end
methods
function value = get.foo(obj)
if isempty(obj.foo)
value = load('foo.mat');
disp('load foo.mat');
end
end
function obj = set.foo(obj,value)
obj.foo = value;
end
end
end
【问题讨论】:
“无法正常工作”的意思是……究竟是什么?您的示例运行良好。 好点来更好地解释它。使用我发布的脚本,例如,每次执行 object.foo 时,它都会加载 foo.mat 文件,而不是只加载一次。 Default Property 可能是更好的选择。 我不想要默认属性,因为它非常大。我只想在调用的时候加载,加载一次。 【参考方案1】:这里有两个主要问题:
在您的get.foo
方法中,一旦您加载了值,就永远不会更新对象中foo
的值,因此它保持为空。
即使您尝试在get.foo
方法中更新foo
,它在原始 对象中仍然是空的,因为您的foobar
类是value class。修改值类对象的方法必须将修改后的对象作为输出返回,因为它们本质上是在修改对象的副本。值类的set
方法返回用于覆盖原始对象的修改对象,但get
方法不返回修改对象(因为通常不希望它们修改它们)。要绕过这个限制,您需要 handle class 的类似引用行为(这里是 a related question,您可能需要查看更多背景信息)。
因此,为了获得您想要的行为,您必须将 foobar
实现为句柄类的子类,并在首次加载时更新 foo
字段:
classdef foobar < handle % Inherit from handle class
properties(Transient = true)
foo
end
methods
function value = get.foo(obj)
if isempty(obj.foo)
value = load('foo.mat');
disp('load foo.mat');
obj.foo = value; % Update foo
end
value = obj.foo; % Return current foo value
end
function set.foo(obj, value) % Return value is unnecessary for handle class
obj.foo = value;
end
end
end
这应该会为您提供您想要的行为(即 foo
仅在首次访问时加载)。
注意: 任何调用get.foo
的方法都将初始化foo
。您可能会忽略的一种方法是disp
方法,因为它是默认为类创建的。 default display for a class object 将显示类名,后跟非隐藏公共属性列表及其值。请注意,当我从上面创建带有和不带分号的 foobar
类对象时会发生什么:
>> f = foobar; % Display is suppressed
>> f = foobar
f =
load foo.mat % foo gets initialized...
foobar with properties:
foo: [1×1 struct] % ...because its value is displayed here
如果您想避免这种情况,您可以将overload the disp
function 用于您的foobar
对象,这样显示对象就不会访问(并因此初始化)foo
。比如可以在上面的foobar
类中加入这个方法:
function disp(obj)
disp(' foobar object');
end
现在你不会在显示对象时初始化foo
:
>> f = foobar
f =
foobar object % foo not yet initialized
>> a = f.foo;
load foo.mat % foo initialized because we accessed it
【讨论】:
你的答案几乎是我想要的,但最后一个注释对我来说是个问题。我调用属性foo
的大多数方法都存在于对象中。我只想加载 foo
如果有方法调用它,以便在 foobar
的实例已经存在时不加载属性 foo
。
@SGeurts:我在笔记中添加了更多细节。您所要做的就是重载disp
方法,使其无法访问foo
。
太棒了! set 方法甚至不是我的目的所必需的。我还发现在变量菜单中显示对象会启动加载foo
。我仍然不明白的是为什么需要 Handle 类而不是 Value 类。
@SGeurts:我添加了一些关于值和句柄类的更多细节。希望这能让它更清楚。
我可以将property属性设置为'true',这样就解决了。以上是关于如何按需加载属性?的主要内容,如果未能解决你的问题,请参考以下文章