Problem using str2func for creating a function handle

조회 수: 4 (최근 30일)
Pedro
Pedro 2014년 1월 28일
편집: Stephen23 2022년 1월 1일
Hello!
I have two functions:
%---------
function [ handle_res ] = handle_fun_creation_2( File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = str2func(['@' File_String]);
elseif Type_identifier == 1
handle_res = str2func(['@(t,y)' File_String '(t,y,Value)'] );
end
end
%-------------
and:
%-------------
function [ y ] = test_3( t,x,Var_opt )
y=x+Var_opt(1)+Var_opt(2);
end
%---------------
Could anyone explain me why the following code doesn't work:
%---------------------------
Var_opt = [30 40]';
[handle_4] = handle_fun_creation_2('test_3',1,Var_opt);
[t6,y6] = ode15s(handle_4,[0:1],0);
Undefined function or variable 'Value'.
Error in @(t,y)test_3(t,y,Value)
%---------
But this one does?
%---------
handle_5 = @(t,y)test_3(t,y,Var_opt);
[t7,y7] = ode15s(handle_5,[0:1],0);
I think I'm missing some detail on how str2func works maybe? Thanks in advance.
  댓글 수: 1
Stephen23
Stephen23 2022년 1월 1일
This is just a very indirect and inefficient approach to parameterize a function. Simpler and more efficient:

댓글을 달려면 로그인하십시오.

채택된 답변

Walter Roberson
Walter Roberson 2014년 1월 28일
str2func() does not execute the content of any strings it is passed so it has no idea that the string 'Value' should relate to the parameter named Value.
if isnumeric(Value)
valstr = sprintf('%g', Value);
else
valstr = char(Value);
end
handle_res = str2func(sprintf('@(t,y)%s(t,y,%s)', File_String, valstr));
  댓글 수: 4
Pedro
Pedro 2014년 1월 28일
편집: Pedro 2014년 1월 28일
Not exactly, nonetheless I believe I found a solution using eval and sprintf:
%------------
function [ handle_res ] = handle_fun_creation_2(File_String,Type_identifier,Value )
if Type_identifier == 0
handle_res = sprintf('@%s',File_String);
elseif Type_identifier == 1
handle_res = sprintf('@(t,y)%s(t,y,Value)',File_String);
end
%----------------
[sprint_4] = handle_fun_creation_2('test_3',1,Var_opt);
handle_4 = eval(sprint_4);
[t6,y6] = ode15s(handle_4,[0:1],0);
%------------------
Although I'm not sure about this code's efficiency, it works. Many thanks for your input!
Stephen23
Stephen23 2022년 1월 1일
편집: Stephen23 2022년 1월 1일
"Although I'm not sure about this code's efficiency, it works"
It is not efficient, nor does it work as you think it does.
For example, although you pass the input argument Value to handle_fun_creation_2 it remains totally unused, it is only when you later EVAL the string in the caller workspace that MATLAB will look for a function or variable named Value. You can easily test this by calling handle_fun_creation_2 with complete nonsense for the third input argument and everything will work (as long as the correct Value is defined in the caller workspace!):
sprint_4 = handle_fun_creation_2('test_3',1,{'hello world'}) % 3rd arg = silly cell array
sprint_4 = '@(t,y)test_3(t,y,Value)'
Value = [pi,2/3]; % <----------- must be defined in the calling workspace...
handle_4 = eval(sprint_4) % <--- because this is actually where Value is included.
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % no errors
If Value is not defined in the caller workspace then your code will not work, it will throw an error about Value being undefined (see bottom of this comment). It is clear that my silly Hello World cell array actually does nothing.
But this just seems to be a very indirect and inefficient approach to parameterize a function:
As the documentation shows, a much simpler and more efficient approach is to use an anonymous function:
fn1 = @(x,y)test_3(x,y,Value);
[t7,y7] = ode15s(fn1,0:1,0);
isequal(t6,t7)
ans = logical
1
isequal(y6,y7)
ans = logical
1
and if the function name really is provided as text (suboptimal design, but still simpler and more direct than a special "creation" function returning a string and evaluating it to get a function handle):
fns = 'test_3';
fn2 = str2func(fns);
fn3 = @(x,y)fn2(x,y,Value);
[t8,y8] = ode15s(fn3,0:1,0);
isequal(t6,t8)
ans = logical
1
isequal(y6,y8)
ans = logical
1
And finally, lets try your code when Value is not defined in the caller workspace:
clearvars Value
handle_4 = eval(sprint_4) % looks the same... but is it?
handle_4 = function_handle with value:
@(t,y)test_3(t,y,Value)
[t6,y6] = ode15s(handle_4,0:1,0); % nope.
Unrecognized function or variable 'Value'.

Error in solution>@(t,y)test_3(t,y,Value)

Error in odearguments (line 90)
f0 = feval(ode,t0,y0,args{:}); % ODE15I sets args{1} to yp0.

Error in ode15s (line 152)
odearguments(FcnHandlesUsed, solver_name, ode, tspan, y0, options, varargin);

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

제품

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by