首页 > 解决方案 > 如何按需加载属性?

问题描述

我想按需加载一个属性,但我无法让它工作。我有一个具有瞬态属性的类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

标签: matlaboop

解决方案


这里有两个主要问题:

  1. 在您的get.foo方法中,一旦加载了值,就永远不会更新foo对象中的值,因此它保持为空。

  2. 即使您尝试更新foo您的方法,它在原始对象get.foo中仍然是空的,因为您的类是一个值类。修改值类对象的方法必须将修改后的对象作为输出返回,因为它们本质上是在修改对象的副本。值类的方法返回用于覆盖原始对象的修改对象,但方法不返回修改对象(因为通常不希望它们修改它们)。为了解决这个限制,您需要句柄类的类似引用的行为(这里有一个相关的问题,您可能想查看更多背景信息)。foobarsetget

因此,为了获得您想要的行为,您必须将其实现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。类对象的默认显示将显示类名,后跟非隐藏公共属性及其值的列表。请注意,当我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

如果你想避免这种情况,你可以为你的对象重载disp函数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

推荐阅读