需要类通过句柄公开私有静态函数

Need class to expose a private static function via handle

提问人:skm 提问时间:10/12/2023 最后编辑:Cris Luengoskm 更新时间:10/13/2023 访问量:60

问:

我需要一个特定的类来公开一个私有的静态函数。我通过存储在元胞数组中的匿名函数来执行此操作。下面人为的例子说明了这个问题:

classdef ParamClass
    properties (Constant)
        param_spec = {
            {'param_1', @(x) isnumeric(x) && isscalar(x) && (x > 0)}, ...
            {'param_2', @(x) ParamClass.validate_param_2(x)} ...
            };
    end
    
    properties
        param_1;
        param_2;
    end
    
    methods (Static, Access = 'private')
        function ok = validate_param_2(x)
            ok = isnumeric(x) && isscalar(x) && (x  < 0);
        end 
    end
    
    methods
        function obj = ParamClass(p1, p2)
            opts = parse_my_args(p1, p2, ParamClass.param_spec{:});
            obj.param_1 = opts.param_1;
            obj.param_2 = opts.param_2;
        end
    end
end

function opts = parse_my_args(p1, p2, varargin)
    assert(varargin{1}{2}(p1));
    assert(varargin{2}{2}(p2));
    
    opts.param_1 = p1;
    opts.param_2 = p2;
end

该函数是私有静态的,但我希望它由外部独立函数通过匿名函数包装器调用。但是,我收到以下错误:ParamClass.validate_param_2

使用ParamClass.validate_param_2时出错

无法访问类“ParamClass”中的方法“validate_param_2”。

经过一番思考,这个错误似乎没有必要。该类将函数句柄传递给外部。句柄的内容应该只由班级决定,不应该是任何人的事。难道不应该所有必需的上下文都是匿名函数的一部分吗?当然,我可以通过公开来消除错误,但我想了解错误背后的基本原理。validate_param_2validate_param_2

任何解释为什么需要这种错误的评论将不胜感激。还有其他选择吗?

函数 MATLAB OOP 静态 私有

评论


答:

0赞 Cris Luengo 10/13/2023 #1

这确实是一个奇怪的错误,我认为这没有多大意义。一种解释可能是,在计算属性约束时,类定义在内存中尚未完成,并且函数尚不可用。但同样,没有理由这样做,它可能不是一个有意识的选择(即这是一个错误)。ParamClass.validate_param_2()

作为替代方案,您可以改用本地函数(即在同一文件中在块之后定义的函数)。这样的函数仅在文件中可见,但您可以返回它的句柄,使其可在另一个文件中使用。此本地函数还可以访问类的私有成员。就所有意图和目的而言,它都是一个私有成员,只是它只能在文件中可见 - 目录中定义的类方法将无法看到它。classdef@ParamClass

classdef ParamClass
    properties (Constant)
        param_spec = {
            {'param_1', @(x) isnumeric(x) && isscalar(x) && (x > 0)}, ...
            {'param_2', @validate_param_2} ...
            };
    end
    
    properties
        param_1;
        param_2;
    end
    
    methods
        function obj = ParamClass(p1, p2)
            opts = parse_my_args(p1, p2, ParamClass.param_spec{:});
            obj.param_1 = opts.param_1;
            obj.param_2 = opts.param_2;
        end
    end
end

function opts = parse_my_args(p1, p2, varargin)
    assert(varargin{1}{2}(p1));
    assert(varargin{2}{2}(p2));
    
    opts.param_1 = p1;
    opts.param_2 = p2;
end

function ok = validate_param_2(x)
    ok = isnumeric(x) && isscalar(x) && (x < 0);
end

评论

0赞 skm 10/13/2023
谢谢。这或多或少解决了问题。另一个问题,与确切的问题没有直接关系,我昨天没有注意到,在我的示例代码中,为了方便起见,我将函数 parse_my_args“ 放在类文件中。然而,尽管在类文件中,Matlab 不允许它通过元胞数组访问类私有静态“validate_param_2”,这从错误中可以明显看出。
0赞 skm 10/13/2023
好的,很抱歉继续这个,但是在您发布的修改后的代码中,您已将@(x) ParamClass.validate_param_2(x)替换为@validate_param_2。后者有效,但前者不起作用,matlab 给出错误(发生在 parse_my_args 函数中)“无法识别的函数或变量'validate_param_2”。不幸的是,在原始代码中,我需要匿名包装器,因为还涉及其他变量。
0赞 Cris Luengo 10/13/2023
@skm 回复您的第二条评论:使用 .从技术上讲,它不是 的成员,因此无效。回复您的第一条评论:我不确定您在这里问什么。“从错误中可以明显看出。”什么错误?您如何尝试访问该类私有静态函数,什么是“通过元胞数组”?@(x) validate_param_2(x)ParamClassParamClass.validate_param_2
0赞 skm 10/13/2023
一旦我把validate_param_2带到类之外并把它变成一个本地函数,我就通过元胞数组访问它,该数组现在包含匿名函数@(x) validate_param_2(x)(注意:没有类命名空间 - 第二条评论中有一个错别字)。但是我收到错误“无法识别的函数或变量'validate_param_2”。
0赞 skm 10/13/2023
关于我的第一条评论,我的意思是,如果“parse_my_args”在类文件中,并且 Matlab 允许类文件本地函数访问私有类成员,那么理论上,原始帖子中的初始问题应该永远不会发生。