MATLAB 函數(shù)(二)


概述

盡可能趁有空更一次的 MATLAB 筆記。

這次內(nèi)容講講 MATALB 中的函數(shù)的高級(jí)部分。

  • MATLAB 函數(shù)的原理:使用函數(shù)的好處在于簡(jiǎn)化了代碼同時(shí)增加了代碼的可讀性。但是在使用函數(shù)的時(shí)候可能會(huì)有一些有偏差的理解,因此需要從機(jī)器的尺度上取解釋 MATLAB 函數(shù)的原理。
  • MATLAB 可選參數(shù):同一個(gè)可能要求不同的使用方法,如果逐一編寫單獨(dú)的函數(shù)實(shí)現(xiàn)不僅浪費(fèi)而且難以使用,因此調(diào)用函數(shù)的使用要能夠自適應(yīng)不同的輸入?yún)?shù)和輸出參數(shù)。
  • MATLAB 函數(shù)的其他類型:MATLAB 官方定義 MATLAB 函數(shù)有四種其他類型:匿名函數(shù)、局部函數(shù)、嵌套函數(shù)和私有函數(shù)。(私以為前兩種可能更常用)

MATLAB 函數(shù)的原理

對(duì)于某一個(gè) MATLAB 函數(shù)而言,它就像一個(gè)黑盒子(Black Box),用戶只需要知道函數(shù)的用途而不必知道函數(shù)內(nèi)部是怎么實(shí)現(xiàn)的。在主程序調(diào)用函數(shù)時(shí),計(jì)算機(jī)開(kāi)辟另一塊內(nèi)存空間,進(jìn)入函數(shù)內(nèi)部,運(yùn)行函數(shù)命令,函數(shù)運(yùn)行結(jié)束后,系統(tǒng)自動(dòng)將這塊內(nèi)存空間回收,除了輸出參數(shù)以外的所有函數(shù)內(nèi)容都不再存在。

請(qǐng)務(wù)必記得:在函數(shù)內(nèi)部做的一切不會(huì)對(duì)外部造成任何影響。

以下方這個(gè)函數(shù)為例

function add_1(x)
    x = x + 1;
    disp(['In function: x = ' num2str(x)]);
end

運(yùn)行如下命令

x = 1;
add_1(x); % 在函數(shù)內(nèi)部,x 的值被修改了
disp(['In main: x = ' num2str(x)]); % 主程序的 x 并沒(méi)有被修改

結(jié)果得到

In function: x = 2
In main: x = 1

這又是什么情況呢?事實(shí)上,兩個(gè) x 是不同的值(函數(shù)并不執(zhí)行“手遞手式”地傳遞參數(shù),而是將原來(lái)的變量拷貝一份放進(jìn)函數(shù)的內(nèi)存空間中),因此修改了函數(shù)內(nèi)部的 x 后,在函數(shù)結(jié)束時(shí)就被回收,而外部的 x 并沒(méi)有受到任何影響。

你可以將主程序的 x 替換成 a ,并在函數(shù)內(nèi)部的“x = x + 1;”添加斷點(diǎn)(只需單擊每一行最左側(cè)行號(hào)后的區(qū)域,即顯示一個(gè)紅色的斷點(diǎn);再次單擊可以取消斷點(diǎn))。運(yùn)行時(shí),會(huì)在函數(shù)內(nèi)部暫停,觀察 Workspace 可以發(fā)現(xiàn)函數(shù)內(nèi)部的 x = 1。點(diǎn)擊工具欄中的 Continue 則可以繼續(xù)運(yùn)行看到主程序仍然是 a = 1。

a = 1;
add_1(a); % 在函數(shù)內(nèi)部,x 的值被修改了
disp(['In main: a = ' num2str(a)]); % 主程序的 a 并沒(méi)有被修改

由此可見(jiàn),函數(shù)內(nèi)部的變量在主程序中是“看不見(jiàn)”,函數(shù)內(nèi)部無(wú)法使用主程序中的變量,同樣地,主程序也無(wú)法使用函數(shù)內(nèi)部的變量。因此,函數(shù)與主程序的“交流”就依賴于輸入?yún)?shù)和輸出參數(shù)。

將函數(shù)需要使用的變量傳入,將函數(shù)計(jì)算所得結(jié)果傳出。

MATLAB 可選參數(shù)

MATLAB 中的許多函數(shù)都有著各種靈活的輸入方式,可以支持不同數(shù)量的輸入?yún)?shù)和輸出參數(shù),比如常用的 zeros 函數(shù)就可以根據(jù)不同數(shù)量的輸入?yún)?shù)創(chuàng)建不同維度的零矩陣。這種靈活性就基于 MATLAB 函數(shù)中的可選參數(shù)。

MATLAB 提供的可選參數(shù)有如下:

  • nargin 函數(shù)輸入?yún)?shù)數(shù)目
  • nargout 函數(shù)輸出參數(shù)數(shù)目
  • varargin 可變長(zhǎng)度輸入?yún)?shù)列表
  • varargout 可變長(zhǎng)度的輸出參數(shù)列表
  • narginchk 驗(yàn)證輸入?yún)?shù)數(shù)目
  • nargoutchk 驗(yàn)證輸出參數(shù)數(shù)目
  • validateattributes 檢查數(shù)組的有效性
  • validatestring 檢查文本的有效性
  • inputParser 函數(shù)的輸入解析器
  • inputname 函數(shù)輸入的變量名稱
  • mfilename 當(dāng)前正在運(yùn)行的代碼的文件名

樣例一:對(duì)于不同輸入?yún)?shù)執(zhí)行不同操作

有時(shí)候?qū)τ谝粋€(gè)函數(shù)希望有多種的調(diào)用方式時(shí),使用可選參數(shù) nargin。同理對(duì)于不同的輸出參數(shù)采用不同的調(diào)用方式時(shí),使用可選參數(shù) nargout。

function report_name_id(name,id)
    switch nargin % 在函數(shù)中 nargin 就是調(diào)用函數(shù)時(shí)輸入?yún)?shù)的數(shù)量
        case 2
            disp(['name: ' name ' id:' num2str(id)]); 
            % 兩個(gè)輸入?yún)?shù)時(shí)輸出名字和 id
        case 1
            disp(['name: ' name ' without id information.']);
            % 僅輸入一個(gè)參數(shù)名字(就是第一個(gè)參數(shù))時(shí)輸出名字和 無(wú) id 信息
        otherwise
            disp('null');
            % 不給輸入?yún)?shù)時(shí),輸出 null。
    end
end

執(zhí)行以下命令

report_name_id('Tom',153412); % 兩個(gè)輸入?yún)?shù)時(shí)輸出名字和 id
report_name_id('Tom'); % 輸出名字和 無(wú) id 信息
report_name_id(); % 輸出 null

樣例二:對(duì)于未知數(shù)量參數(shù)執(zhí)行不同操作

有時(shí)候調(diào)用函數(shù)甚至不知道有多少個(gè)輸入?yún)?shù)時(shí),又該如何處置呢?這時(shí)就可以使用 varargin 來(lái)接收任意個(gè)輸入?yún)?shù),通過(guò) varargin{index)}來(lái)訪問(wèn)對(duì)應(yīng)的輸入?yún)?shù)。

function information_items(name,varargin)
    disp(name);
    for index = 1:nargin-1
        disp(varargin{index});
    end
end

三種調(diào)用方式會(huì)導(dǎo)致不同的結(jié)果,可以看到 varargin 都可以將多余的任意數(shù)量個(gè)參數(shù)都取得,并且可以通過(guò) varargin{index}來(lái)訪問(wèn)。(事實(shí)上,varargin 是一個(gè) cell 型變量)

information_items('Tom','height:180','weight:72kg','age:17');
information_items('Jack','height:169','weight:74kg');
information_items('Bill','height:171','weight:88kg','age:23','shcool:Stanford');

同理,也可以對(duì)應(yīng)地向 varargout{index} 賦值,將任意數(shù)量個(gè)輸出參數(shù)傳出。

樣例三:驗(yàn)證輸入?yún)?shù)數(shù)目

narginchk 是基于給定的輸入?yún)?shù)上下限來(lái)驗(yàn)證輸入?yún)?shù)是否符合要求的命令。

function two_or_three_inputs(varargin)
    narginchk(2,3);
    disp('There are two or three inputs');
end

同樣使用三種調(diào)用方式

two_or_three_inputs(1); % 報(bào)錯(cuò) error,輸入?yún)?shù)不夠
two_or_three_inputs(1,1);
two_or_three_inputs(1,1,1,1); % 報(bào)錯(cuò) error,輸入?yún)?shù)過(guò)多

同理也可以使用 nargoutchk 對(duì)輸出參數(shù)驗(yàn)證,此外,不妨嘗試自己使用 error 函數(shù)給出合適的調(diào)用函數(shù)提示信息。

樣例四:函數(shù)輸入的變量名稱

你可能會(huì)想函數(shù)輸入的變量名稱肯定是已知的,為什么還要特地設(shè)計(jì)這樣一個(gè)函數(shù)呢?這個(gè)函數(shù)是有一定作用的。

function y = data_to_string(varargin)
    y = [];
    for index = 1:nargin
        y = [y inputname(index) ':' varargin{index} ';'];
    end
end

這個(gè)函數(shù)可以將數(shù)據(jù)根據(jù)對(duì)應(yīng)的變量類型串成一個(gè)數(shù)據(jù)包。

name = 'Tom';
age = '18';
height = '180cm';
weight = '70kg';
str = data_to_string(name,age,height,weight);

MATLAB 函數(shù)其他類型

MATLAB 官方確定的其他類型的函數(shù)包括四種:

  • 匿名函數(shù)
  • 局部函數(shù)
  • 嵌套函數(shù)
  • 私有函數(shù)

匿名函數(shù)

匿名函數(shù)是僅包含一句 MATLAB 命令的函數(shù)。匿名函數(shù)的優(yōu)點(diǎn)在于無(wú)需另外創(chuàng)建保存一個(gè) m 文件,甚至可以在腳本文件和命令行中隨時(shí)定義隨時(shí)使用。形如下式的命令可以創(chuàng)建一個(gè)匿名函數(shù):

fun = @(x,y)x.^2+y.^2-2*x*y+4;

其中 fun 是函數(shù)句柄,@ 運(yùn)算符則用于創(chuàng)建一個(gè)句柄。

局部函數(shù)

局部函數(shù)也叫做子函數(shù),相當(dāng)于某個(gè)完整函數(shù)的附屬函數(shù)。局部函數(shù)編寫于某個(gè)函數(shù)最后一行之后,是該函數(shù)的附屬函數(shù)。這意味著局部函數(shù)使用范圍有限:僅能被同一個(gè)文件中的其他函數(shù)調(diào)用,對(duì)其他函數(shù)和命令行不可見(jiàn)。

function [avg, med] = mystats(x)
% 主函數(shù) 可以被外部檢索調(diào)用
n = length(x);
avg = mymean(x,n);
med = mymedian(x,n);
end

function a = mymean(v,n)
% 子函數(shù) 1 
% 只能被主函數(shù)和其他子函數(shù)調(diào)用
a = sum(v)/n;
end

function m = mymedian(v,n)
% 子函數(shù) 2
% 只能被主函數(shù)和其他子函數(shù)調(diào)用
w = sort(v);
if rem(n,2) == 1
    m = w((n + 1)/2);
else
    m = (w(n/2) + w(n/2 + 1))/2;
end
end

特別地,如果你習(xí)慣省略函數(shù)體結(jié)尾的 end,在同一個(gè)文件中應(yīng)當(dāng)保證子函數(shù)和主函數(shù)使用同一種格式。

嵌套函數(shù)

嵌套函數(shù)是定義在函數(shù)中的函數(shù),外層函數(shù)可以調(diào)用內(nèi)層函數(shù)并且如果內(nèi)層函數(shù)變量在外層函數(shù)中有定義,那么嵌套函數(shù)可以訪問(wèn)和修改在其父函數(shù)中定義的變量。

function main1
x = 5;
nestfun1

   function nestfun1 
     x = x + 1;
   end 

end

私有函數(shù)

假設(shè)當(dāng)前工作路徑為 “/xxx”,在文件夾 xxx 創(chuàng)建一個(gè)名為“private”子文件夾,可以指定一個(gè)函數(shù)為私有函數(shù)。這樣一來(lái),只有文件夾 xxx下的函數(shù)可以調(diào)用這個(gè)私有函數(shù)。

小結(jié)

到此函數(shù)的內(nèi)容也告一段落,本文除了 MATLAB 函數(shù)的內(nèi)容外,還有一個(gè)額外的點(diǎn)就是斷點(diǎn)調(diào)試(快速地中斷和保留中斷時(shí)的變量,能夠讓你加快調(diào)試的步驟)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容