目录
第9章:函数
9.1 使用 function 关键字来创建函数
9.1.1 函数的例子和功能
简单输出函数
计算两个数的和与差
MATLAB内置函数调用
函数调用的特殊情况与灵活性
输入参数的灵活性
输出值的灵活性
查看内置函数源代码
type 函数名(如type rgb2gray)
type 函数名.m(如type rgb2gray.m)
使用编辑器打开对应的.m文件
内置函数的优势
9.1.2 函数的创建和运行
使用function关键字创建函数的语法
创建、保存和调用第一个自定义函数
创建步骤
示例
调用方法
形式参数和实际参数(形参和实参)
形式参数(形参)
实际参数(实参)
重要区别
函数工作的本质(基础和函数工作区)
基础工作区(Base Workspace)
函数工作区(Function Workspace)
工作区特点
使用断点调试功能揭示函数的工作过程
断点调试步骤
使用调试工具栏按钮控制执行流程
调试示例
在自定义函数中调用另一个自定义函数
return关键字:将控制权交还给调用脚本或函数
使用场景
示例
使用global关键字声明全局变量
语法
使用规则
示例
使用persistent关键字声明持久变量
语法
特点
示例
常见错误场景
函数名与文件名不匹配
函数路径问题
输入输出参数数量不匹配
变量作用域混淆
函数递归调用导致栈溢出
使用dbstop if error进行错误调试
基本用法
调试流程
示例
9.1.3 函数的高级用法
函数高级用法总结表
实时函数
局部函数
示例
嵌套函数
示例
可变数量的输入参数或输出值
nargin和nargout
Varargin
Varargout
narginchk和nargoutchk
arguments代码块
递归函数
示例(计算阶乘)
第9章:函数
9.1 使用 function 关键字来创建函数
在数学中,函数是一种将输入值映射到输出值的关系;
在计算机中,函数是一段可重复使用的代码块,用于执行特定任务并返回结果。
函数的主要作用是提高代码的模块化程度、减少重复代码、增强程序的可读性和可维护性。
9.1.1 函数的例子和功能
函数类别 | 函数名 | 功能描述 |
数学运算 | abs(z) | 求复数z的模,或字符串转ASCII值 |
数学运算 | factorial(n) | 计算n的阶乘 |
数学运算 | nchoosek(n,k) | 计算组合数C(n,k) |
逻辑判断 | all(A) | 若向量A的所有元素非零则结果为1 |
方程求解 | solve | 求解方程,得到全部符号解 |
方程求解 | vpasolve | 求解方程的数值近似解 |
方程求解 | fsolve | 求解非线性方程组 |
方程求解 | fzero | 求解一维函数的零点 |
方程求解 | roots | 求解多项式的根 |
简单输出函数
function hello()disp('Hello, MATLAB!');end
可以直接调用:hello()
计算两个数的和与差
function [sum, diff] = calculate(a, b)sum = a + b;diff = a - b;end
调用方式:[s, d] = calculate(10, 5)
MATLAB内置函数调用
MATLAB提供了丰富的内置函数,可以直接调用使用。
例如:
- abs(z): 求复数z的模,也可将字符串转化为ASCII值
- all(A): 若向量A的所有元素非零则结果为1
- nchoosek(n,k): 求组合数C(n,k)
- factorial(n): 求n的阶乘
函数调用的特殊情况与灵活性
输入参数的灵活性
- 可以定义具有默认值的参数
- 可以使用varargin处理可变数量的输入参数
- 可以根据输入参数的类型和数量执行不同的操作
输出值的灵活性
- 函数可以有多个输出值,如[sum, diff] = calculate(a, b)
- 如果调用函数时不指定输出变量,结果将存储在默认变量ans中
- 可以使用varargout处理可变数量的输出参数
查看内置函数源代码
type 函数名(如type rgb2gray)
type 函数名.m(如type rgb2gray.m)
使用编辑器打开对应的.m文件
内置函数的优势
- 经过优化,执行效率高
- 代码经过严格测试,可靠性高
- 提供了丰富的功能,覆盖科学计算的各个方面
- 与MATLAB环境无缝集成,使用方便
9.1.2 函数的创建和运行
知识点 | 语法/方法 | 说明 | 示例 |
函数定义 | function [输出] = 函数名(输入) | 使用function关键字定义函数 | function area = circleArea(r) |
函数调用 | 变量 = 函数名(参数) | 调用已定义的函数 | a = circleArea(5); |
形参和实参 | - | 形参是函数定义中的参数,实参是调用时传入的值 | function area = circleArea(radius)中radius是形参,circleArea(5)中5是实参 |
断点设置 | 点击行号左侧或使用dbstop | 在代码中设置断点进行调试 | dbstop in circleArea at 3 |
return语句 | return | 提前终止函数执行 | if x < 0; return; end |
全局变量 | global 变量名 | 声明可在多个函数间共享的变量 | global counter; |
持久变量 | persistent 变量名 | 声明在函数调用间保持值的变量 | persistent callCount; |
错误调试 | dbstop if error | 在错误发生时自动进入调试模式 | dbstop if error |
使用function关键字创建函数的语法
function [输出参数1, 输出参数2, ...] = 函数名(输入参数1, 输入参数2, ...)% 函数说明注释% 函数体% 执行特定任务的代码end
创建、保存和调用第一个自定义函数
创建步骤
- 在MATLAB编辑器中新建一个.m文件
- 使用function关键字定义函数
- 将文件保存为与函数名相同的名称(例如函数名为myFunction,则文件应保存为myFunction.m)
示例
创建一个计算圆面积的函数
function area = circleArea(radius)% 计算圆的面积% 输入:radius - 圆的半径% 输出:area - 圆的面积area = pi * radius^2;end
调用方法
% 在命令窗口或其他脚本中调用r = 5;a = circleArea(r); % a将得到圆的面积disp(['半径为', num2str(r), '的圆的面积是:', num2str(a)]);
形式参数和实际参数(形参和实参)
形式参数(形参)
函数定义中使用的参数,如上面例子中的radius
实际参数(实参)
调用函数时传入的实际值,如上面例子中的r
重要区别
- 形参只在函数内部有效,是函数的局部变量
- 实参是调用函数时提供的具体值或变量
- 函数调用时,实参的值会传递给对应的形参
函数工作的本质(基础和函数工作区)
基础工作区(Base Workspace)
MATLAB命令行和脚本所在的工作区
函数工作区(Function Workspace)
每个函数独立的工作区
工作区特点
- 函数工作区与基础工作区是隔离的
- 函数内部定义的变量只在函数内部有效
- 函数不能直接访问其他工作区的变量(除非使用global或persistent关键字)
- 函数调用结束后,其工作区中的变量会被销毁
使用断点调试功能揭示函数的工作过程
断点调试步骤
- 在MATLAB编辑器中,点击代码行号左侧设置断点(红色圆点)
- 运行函数
- 程序执行到断点处会暂停
使用调试工具栏按钮控制执行流程
- Continue:继续执行到下一个断点或程序结束
- Step:单步执行(进入函数)
- Step In:进入函数内部
- Step Out:跳出当前函数
调试示例
function [sum, product] = calculate(a, b)% 设置断点在这一行sum = a + b; % 断点1product = a * b; % 断点2end
通过断点可以观察变量值的变化,理解函数执行过程。
在自定义函数中调用另一个自定义函数
function result = computeStatistics(data)% 主函数:计算数据的统计信息% 调用其他自定义函数avg = calculateAverage(data);med = calculateMedian(data);result = struct('average', avg, 'median', med);endfunction avg = calculateAverage(data)% 计算平均值avg = sum(data) / length(data);endfunction med = calculateMedian(data)% 计算中位数sortedData = sort(data);n = length(sortedData);if mod(n, 2) == 0med = (sortedData(n/2) + sortedData(n/2 + 1)) / 2;elsemed = sortedData((n + 1) / 2);endend
return关键字:将控制权交还给调用脚本或函数
return关键字用于提前终止函数执行,并将控制权返回给调用者。
使用场景
- 满足特定条件时提前退出函数
- 错误处理
示例
function result = checkPositive(num)% 检查数字是否为正数if num <= 0disp('输入不是正数');result = [];return; % 提前退出函数endresult = num;disp(['输入是正数: ', num2str(num)]);end
使用global关键字声明全局变量
全局变量可以在多个函数和基础工作区之间共享。
语法
global 变量名1 变量名2 ...
使用规则
- 在每个需要访问全局变量的函数中,都必须使用global关键字声明
- 全局变量在程序运行期间一直存在
- 应谨慎使用全局变量,以免造成代码混乱
示例
function setGlobalValue(value)global globalVar; % 声明全局变量globalVar = value;endfunction displayGlobalValue()global globalVar; % 声明全局变量disp(['全局变量的值是: ', num2str(globalVar)]);end% 在命令窗口中setGlobalValue(42);displayGlobalValue(); % 显示: 全局变量的值是: 42
使用persistent关键字声明持久变量
持久变量类似于其他编程语言中的静态变量,它们在函数调用之间保持其值。
语法
persistent 变量名1 变量名2 ...
特点
- 持久变量只在声明它的函数内部可见
- 函数调用结束后,持久变量的值不会被清除
- 当MATLAB会话结束或清除函数时,持久变量才会被清除
- 持久变量只在第一次调用函数时初始化
示例
function counter = callCounter()persistent count; % 声明持久变量% 第一次调用时初始化if isempty(count)count = 0;endcount = count + 1;counter = count;disp(['函数已调用次数: ', num2str(counter)]);end% 在命令窗口中多次调用callCounter(); % 显示: 函数已调用次数: 1callCounter(); % 显示: 函数已调用次数: 2callCounter(); % 显示: 函数已调用次数: 3
常见错误场景
函数名与文件名不匹配
错误:函数名为calculateArea,但文件保存为area.m
解决:确保文件名与函数名完全一致
函数路径问题
错误:函数文件不在MATLAB的搜索路径中
解决:使用addpath添加路径或将文件放在当前工作目录
输入输出参数数量不匹配
错误:函数定义需要2个输出参数,但调用时只提供1个
解决:检查函数定义和调用语句
变量作用域混淆
错误:试图在函数外部访问函数内部变量
解决:使用适当的参数传递或全局变量
函数递归调用导致栈溢出
错误:无限递归调用
解决:确保递归有终止条件
使用dbstop if error进行错误调试
dbstop if error是MATLAB中强大的调试工具,它可以在发生错误时自动暂停程序执行,进入调试模式。
基本用法
dbstop if error % 在任何错误发生时停止dbstop if caught error % 在被try-catch捕获的错误处停止dbstop if warning % 在警告发生时停止dbstop if naninf % 在NaN或Inf值产生时停止dbstop if error -identifier 特定错误ID % 只在特定错误发生时停止
调试流程
- 在命令窗口输入dbstop if error
- 运行可能导致错误的代码
- 当错误发生时,MATLAB会自动暂停并进入调试模式
- 检查变量值,分析错误原因
- 使用调试命令逐步执行代码
- 找到并修复错误后,使用dbclear all清除所有断点
示例
% 假设有以下函数function result = divideNumbers(a, b)result = a / b;end% 在命令窗口中dbstop if error % 设置错误断点divideNumbers(10, 0); % 这将导致除以零错误,程序会自动暂停
当错误发生时,可以检查K>>提示符下的变量值,理解错误原因。
9.1.3 函数的高级用法
函数高级用法总结表
功能类型 | 说明 | 语法示例 | 特点 |
实时函数 | 用于实时数据分析的函数 | function output = realTimeFunction(input) | 可实时处理数据并即时输出结果 |
局部函数 | 同一文件中的辅助函数 | function output = localFunction(input) | 只能被同一文件中的其他函数调用 |
嵌套函数 | 定义在函数内部的函数 | function parentFunction | 可访问父函数工作区中的变量 |
可变输入参数 | 接受任意数量输入的函数 | function output = varArgFunction(varargin) | 使用varargin收集所有输入参数 |
可变输出参数 | 返回任意数量输出的函数 | function varargout = varOutFunction(input) | 使用varargout返回多个输出 |
参数验证 | 验证和限制函数参数 | arguments | 自R2019b起支持,可设置参数类型、大小和约束 |
递归函数 | 调用自身的函数 | function result = fact(n) | 需要明确的停止条件 |
实时函数
实时函数是MATLAB中用于实现实时数据分析的工具,能够在程序运行过程中不断接收输入数据并即时输出结果,非常适用于需要实时更新的应用场景,如数据采集、信号处理等。
实时函数的创建与普通函数类似,但具有实时数据处理能力,可以在实时脚本中使用,提供动态更新的可视化效果。
局部函数
在MATLAB中,一个函数文件可以包含多个函数,其中第一个函数称为主函数,其他函数称为局部函数。
主函数可以被外部调用,而局部函数只能被同一文件中的其他函数调用,无法直接被外部调用。
示例
function mainFunction()% 主函数result = localFunction(5);disp(result);endfunction output = localFunction(input)% 局部函数output = input * 2;end
嵌套函数
嵌套函数是完全包含在父函数内部的函数,可以出现在函数体内的任何位置,以function声明,以end结束。
嵌套函数可以访问父函数工作区中的变量,这是它与局部函数的主要区别。
示例
function parentFunctionx = 10;function nestedFunction% 可以访问父函数的变量xdisp(['x的值是: ', num2str(x)]);endnestedFunction();end
可变数量的输入参数或输出值
nargin和nargout
用于获取函数输入和输出参数的数目
Varargin
可变长度输入参数列表,允许函数接受任意数量的输入参数
Varargout
可变长度的输出参数列表,允许函数返回任意数量的输出值
narginchk和nargoutchk
用于验证输入和输出参数数目
示例
function varargout = flexibleFunction(varargin)% 输入参数数量numInputs = nargin;disp(['输入参数数量: ', num2str(numInputs)]);% 处理输入参数for i = 1:numInputsdisp(['第', num2str(i), '个参数: ', num2str(varargin{i})]);end% 根据输入参数数量决定输出参数数量if nargout == 0% 无输出return;elseif nargout == 1% 单个输出varargout{1} = sum(cell2mat(varargin));else% 多个输出for i = 1:nargoutif i <= numInputsvarargout{i} = varargin{i} * 2;elsevarargout{i} = 0;endendendend
arguments代码块
参数声明或验证
自R2019b版本起,MATLAB引入了arguments代码块,用于函数参数的声明和验证。arguments对象表示函数的实参集合,仅在函数体内可见,并可以直接访问。
示例
function validatedFunction(x, y)argumentsx (1,1) double {mustBePositive, mustBeInteger} = 10;y (1,:) string = "default";end% 函数体disp(['x的值: ', num2str(x)]);disp(['y的值: ', y]);end
递归函数
递归是指在函数体内调用自身的编程技术。
在MATLAB中,递归函数的定义与其他编程语言类似,需要明确定义停止条件,否则可能导致无限递归和栈溢出。
示例(计算阶乘)
function result = factorial(n)% 停止条件if n == 0 || n == 1result = 1;else% 递归调用result = n * factorial(n-1);endend