问题
I need something similar to evalin
, but original evalin
of Matlab cannot be used recursively. For example, I have function f0 which calls 2 other functions f11 and f12:
function f0()
[v1, v2] = deal(1, 1);
f11();
f12();
disp(v1);
end
Functions f11 and f12 use variable v1, and both call function f2:
function f11()
v1 = evalin('caller', 'v1');
f2();
assignin('caller', 'v1', v1);
end
function f12()
v1 = evalin('caller', 'v1');
f2();
assignin('caller', 'v1', v1);
end
And the function f2 should use both variables v1 and v2 of f0's workspace:
function f2()
v1 = evalin('caller', 'v1'); % get variable v1 from f11 or f12
% since there is already a variable v1
% in f11 and f12's workspaces
% TODO: get v2 from f0
if v2 == 1
v1 = v1 + 1;
end
assignin('caller', 'v1', v1);
end
Is there anyway to make the TODO possible without using v2 = evalin('caller', 'v2')
in f11 and f12 ?
回答1:
This is possibly one of the worst way of organising your data transfer between functions. Workspaces of functions are separated for a good reason, to keep things clean and organised.
You are trying to bypass all safeguards put in place by people who designed this language (and many other language who share this separation of workspace/scope). These "bypass" functions are available in Matlab for punctual usage when you are prototyping. They are not intended for heavy usage or for final solution (most of them won't be compilable actually).
It is
- potentially ultra confusing (for you later on, but even worse if someone else has to use your code).
- very hard to debug (you almost have to know the value of a variable in advance to know if the import from another workspace was right).
You say in the comment that passing variable as parameter is complicated because of their number, but every time you call something like x = evalin('caller', 'x');
you have to write 1 full line of code to retrieve your value anyway. And then assignin('caller', 'x', x);
is another line of code to send it back ... that's madness.
Would it not be simpler (and shorter) to just have x
in your function input parameters ?? (it is still faster to have 100 variables in input than to have 200 full lines of codes to retrieve then resend these values from uncertain locations).
Recommended (if practical): pass variable in parameter
To make variable passing easy you could for example gather them all in a structure (or a cell array):
[v1, v2] = deal(1, 1);
myVars.v1 = v1 ;
myVars.v2 = v2 ;
myVars = f11(myVars); %// you only have one variable to pass into your functions
myVars = f12(myVars); %// just make sure you retrieve it in output too
disp(myVars.v1);
And then
function myVars = f11()
myVars = f2(myVars);
end
And so on, as long as you pass the variable to the next function, then retrieve it in output, this would work with any level of recursion.
Recommended (if above not possible): Use nested functions
If you define your function f11()
inside your f0()
, the variable which have the same name in the 2 functions will be shared (visible by at both levels). Read the documentation for more detail. This way you would not need your numerous call to evalin/assignin
because the variable is know everywhere. Your function would have to be written in this form:
function f0()
[v1, v2] = deal(1, 1);
f11();
f12();
disp(v1);
function f11()
f2();
function f2()
if v2 == 1
v1 = v1 + 1;
end
end
end %// END function F11
function f12()
f2();
function f2()
if v2 == 1
v1 = v1 + 1;
end
end
end %// END function F12
end %// END function F0
Stack Exchange does not render that, but in the Matlab editor you could notice that the "shared" variable will be highlighted in a different colour (to alert you that they have a different scope than standard variable).
If I run f0()
I do get:
>> f0
3
Which was the expected result. The only downside, as you can see, is that if you are calling f2()
from within f11()
and f12()
, the function f2()
has to be written within each of them (so a bit of copy/paste). Unless at this level of recursion you do not have too many variable to pass so you could consider writing f2()
on the side and using the standard variable passing scheme.
Can work, but not recommended
Now if you are still keen on writing numerous lines of codes just to pass single variables around, there are still 2 options:
- use global variables
- use setappdata and getappdata
I do not like to use global
so I won't detail here. Just remember that for a variable to be really global
it has to be declared as global
in every function where it is used.
For the appdata
method, you need a "container" which will be accessible to all your functions. You can use the "root" object for that (identifier: 0
).
So for example, when you want to store a variable you could use:
setappdata( 0 , 'v2' , v2 ) %// store the value of `v2` in a field named `'v2'` in the root object.
then in any of your function, get the value, work on it then store it back:
function f2()
v1 = getappdata(0,'v1') %// get the value of v1
v2 = getappdata(0,'v2') %// get the value of v2
if v2 == 1
v1 = v1 + 1; %// modify the value of v1
end
v1 = setappdata(0,'v1',v1) %// store the value of v1
end
Apply the same principle in your base function and f11()
, f12()
, etc ... Just remember to always store any value back after you modified it so it is available for the next function which will need it.
回答2:
Just trying to get this right: Your 'Variables' are holding a value that should be consistent over operations that you like to perform on them. Only a shot in the dark, but have you tried Object-Orientation on your problem.
classdef myObj
properties
v1;
v2;
end
methods
function f1(obj)
... do something here ....
obj.v1 = ....;
end
function f2(obj)
obj.f1();
end
end
Depending on your specific problem this might be the easiest way to get recursion right. OO in Matlab isnt that hard to learn.
Hth
回答3:
You can save f0()
's variables to a file and then call a load
method in f2()
to import those variables in f2()
workspace.
来源:https://stackoverflow.com/questions/28081836/matlab-access-variable-in-specific-workspace