注意结尾的 end 是配对的——这和向量下标里的 end 完全不同,虽然写法一样。动作通常缩进两格或四格,让代码一眼看出层级。
4.1.1 第一个例子:把负数变 0
if num < 0 num = 0end
试着在命令行连续敲两次,每次给 num 不同的初值:
>> num = -4;>> if num < 0 num = 0 endnum = 0 % 条件为真,进了 if 内部>> num = 5;>> if num < 0 num = 0 end>> % 条件为假,整个 if 被跳过,啥都没打印
第一次 num 是 -4,条件 num < 0 为真,num 被改成 0;第二次 num 是 5,条件为假,跳过 if 体,直接回到 >> 提示符。
if 也可以直接在命令行输入——敲完一行 if 条件 按 Enter,MATLAB 会进入「等待动作」模式,再敲动作、按 Enter、敲 end、按 Enter,整个 if 才被执行。这对临时调试特别方便,但正式程序里还是放进脚本里更整齐。
4.1.2 脚本里的典型用法:先校验再计算
if 最常见的用法是「先剔除非法输入,再做正常运算」。比如下面这个脚本 sqrtifexamp.m 处理用户输入的数字:负数自动变成 0,再算平方根:
% 文件:sqrtifexamp.m% 提示用户输入一个数并打印平方根;负数先变成 0num = input('Please enter a number: ');if num < 0 num = 0;endfprintf('The sqrt of %.1f is %.1f\n', num, sqrt(num))
>> sqrtifexampPlease enter a number: -4.2The sqrt of 0.0 is 0.0 % 负数被改成 0,sqrt(0)=0>> sqrtifexampPlease enter a number: 1.44The sqrt of 1.4 is 1.2
如果想让脚本对负数更「友好」——告诉用户发生了什么,再改用绝对值——只要把 if 体换成多条语句:
if num < 0 disp('OK, we''ll use the absolute value') % 两个连续单引号 = 打印一个 ' num = abs(num);endfprintf('The sqrt of %.1f is %.1f\n', num, sqrt(num))
>> sqrtifexampiiPlease enter a number: -25OK, we'll use the absolute valueThe sqrt of 25.0 is 5.0
字符串里打单引号:连续两个 ''
MATLAB 字符串用单引号包,打印一个真实的单引号需要写成 ''(两个连续单引号)。这一点在 if 语句的提示语、error 信息里很常见。
4.1.3 临时变量:经典的「交换两个数」
>> a = 3; b = 5;>> temp = a; % 先把 a 的值备份到 temp>> a = b; % 把 b 拷给 a>> b = temp; % 把备份给 b>> aa = 5>> bb = 3
为什么不能直接写 a = b; b = a;?因为 a = b 已经把 a 的原值冲掉了,再 b = a 只是把刚拷过来的 5 再拷给 b,结果两边都变成 5。临时变量(temporary variable)temp 就是用来避免「原值被覆盖」的脚手架。
% 文件:checkradius.m% 计算圆的面积,并对半径做错误检查radius = input('Please enter the radius: ');if radius <= 0 fprintf('Sorry; %.2f is not a valid radius\n', radius)else area = calcarea(radius); fprintf('For a circle with a radius of %.2f,', radius) fprintf('the area is %.2f\n', area)end
>> checkradiusPlease enter the radius: -4Sorry; -4.00 is not a valid radius>> checkradiusPlease enter a radius: 5.5For a circle with a radius of 5.50, the area is 95.03
if vs. if-else 的取舍
教材的 Style Guideline 写得很明确:只要 else 不需要干任何事,就别写 else。例如只想在 unit == 'i' 时把英寸换算成厘米,没有反方向动作——只用一个 if 就够了。多余的 else len = len; 是噪声。
% 文件:printsindegorrad.mangle = input('Enter the angle: ');mode = input('(r)adians (default) or (d)egrees: ', 's');if mode == 'd' val = sind(angle); % sind 接受「度」else val = sin(angle); % sin 接受「弧度」endfprintf('The sin is %.2f\n', val)
>> printsindegorradEnter the angle: 45(r)adians (default) or (d)egrees: dThe sin is 0.71>> printsindegorradEnter the angle: pi(r)adians (default) or (d)egrees: rThe sin is 0.00
注意 mode == 'd' 这种字符串相等比较——左右都用单引号包起来才是字符串字面量。如果一不小心写成 mode == d(没加单引号),MATLAB 会去找变量 d 的值;变量 d 不存在就直接报错。
if strcmp(mode, 'degree') val = sind(angle);elseif strcmp(mode, 'radian') val = sin(angle);else disp('Unknown mode; treating as radians') val = sin(angle);end
% 错误示范:else 啥也没做,写了等于噪声if unit == 'i' len = len * 2.54;else len = len; % 把值赋给自己,等于啥也没干end% 正确写法:省掉无意义的 elseif unit == 'i' len = len * 2.54;end
同样的道理,elseif 后面的条件也不该写冗余判断:
% 错误示范:第二个条件完全多余if number == 5 disp('It is a 5')elseif number ~= 5 disp('It is not a 5')end% 正确写法:else 已经覆盖所有非 5 的情况if number == 5 disp('It is a 5')else disp('It is not a 5')end
if x < -1 y = 1;elseif x <= 2 y = x^2;else y = 4;end
封装成函数 calcy.m,可以直接被脚本调用:
function y = calcy(x)% calcy 根据 x 的范围计算 y% y = 1 if x < -1% y = x^2 if -1 <= x <= 2% y = 4 if x > 2if x < -1 y = 1;elseif x <= 2 y = x^2;else y = 4;endend
嵌套(nested) 级联(cascading) elseif(推荐)
────────────── ──────────────── ────────────────
if 条件1 if 条件1 if 条件1
动作1 动作1 动作1
else elseif 条件2 elseif 条件2
if 条件2 动作2 动作2
动作2 elseif 条件3 else
else 动作3 动作3
if 条件3 else end
动作3 动作n
else end
动作n
end
end
end
常见坑: elseif 中间漏空格
else if(带空格)和 elseif(无空格)是两件不同的事!前者会被解析成「else + 单独的 if」,导致 end 不匹配;后者才是 elseif 子句。每次敲完都看一眼:「我想要的是哪一种?」
4.3.4 嵌套 / 级联 / elseif 的 ASCII 对照图
嵌套 if-else(每一层都是一个完整的 if) elseif(线性一条龙)
────────────────────────────── ─────────────────────
if 条件1 if 条件1
┌─────┐ ┌─────┐
│ 动作1│ │ 动作1│
└──┬──┘ └──┬──┘
else│ elseif 条件2
▼ ┌─────┐
if 条件2 │ 动作2│
┌─────┐ └─────┘
│ 动作2│ elseif 条件3
└──┬──┘ ┌─────┐
else│ │ 动作3│
▼ └─────┘
if 条件3 else
┌─────┐ ┌─────┐
│ 动作3│ │ 动作n│
└──┬──┘ └─────┘
else│ end
▼ ↑ 整个结构只有一个 end
动作 n
end
↑ 每一层都要单独写 end,容易漏
switch quiz case {10, 9} % 多个值用 {} 包起来 grade = 'A'; case 8 grade = 'B'; % ... 其余类似end
otherwise 子句是「前面所有 case 都不匹配时」的兜底分支——可以省略,但教材强烈建议保留(除非真的什么也不做)。otherwise 经常被当作「错误信息」的归集地:
choice = input('Enter a 1, 3, or 5: ');switch choice case 1 disp('It''s a one!!') case 3 disp('It''s a three!!') case 5 disp('It''s a five!!') otherwise disp('Follow directions next time!!')end
>> switcherrorEnter a 1, 3, or 5: 4Follow directions next time!!
ranforce = randi([0, 12]); % 在 [0,12] 里随机取一个整数switch ranforce case 0 disp('There is no wind') case {1, 2, 3, 4, 5, 6} disp('There is a breeze') case {7, 8, 9} disp('This is a gale') case {10, 11} disp('It is a storm') case 12 disp('Hello, Hurricane!')end
if ranforce == 0 disp('There is no wind')elseif ranforce <= 6 disp('There is a breeze')elseif ranforce <= 9 disp('This is a gale')elseif ranforce <= 11 disp('It is a storm')else disp('Hello, Hurricane!')end
注意第二个写法利用了「ranforce 已经在 [0,12]」这一前提,省掉了上界检查。
4.4.3 if vs. switch 的「触发词」
经验上,读需求时如果出现下面这些词,思路应该不一样:
需求关键词
建议结构
「如果…则…否则…」
if / if-else
「满足以下任一条件…」
if + ||
「都不满足…」
if-else 的 else 分支
「当 x 等于 a/b/c/d」
switch
「在 A 区间内…在 B 区间内…」
嵌套 if-else / elseif
「不属于以上任何情况」
otherwise / else
4.4.4 menu 函数:图形化的「switch 触发器」
R2015b 之前的 MATLAB 提供 menu 函数——它弹出一个带按钮的窗口,用户点哪个按钮就返回哪个数字,再交给 switch 处理:
choice = menu('Pick a shape', 'Circle', 'Rectangle', 'Triangle');switch choice case 1 disp('You picked Circle') case 2 disp('You picked Rectangle') case 3 disp('You picked Triangle') otherwise disp('No shape picked')end
因为它们不是关键字,理论上你可以写 sin = 5 把内置的 sin 函数覆盖掉——然后所有用到正弦的代码都会出错**。** 用 clear sin 才能救回来。这条坑教材里没单独列,但属于「MATLAB 给人最大自由度带来的副作用」,要小心。
4.5.4 综合实战:写一个「安全输入」包装函数
把所有学到的 is 函数串起来,可以做一个 getnumber.m:反复提示用户输入数字,直到他输入合法为止:
function n = getnumber(prompt)% getnumber 反复提示,直到用户输入合法数字为止% 调用格式:getnumber('promptString')prompt = [prompt ': ']; % 拼上冒号空格while true s = input(prompt, 's'); % 当字符串读进来,避开变量名陷阱 if isempty(s) disp('Nothing entered, try again') continue end n = str2double(s); % 字符串转数字 if isnan(n) disp('Not a number, try again') continue end break % 输入合法,跳出循环endend
里面用了:
isempty 检查空输入;
str2double 把字符串解析成数字;
isnan 判断「不是数字」的结果(str2double('hello') 返回 NaN);
第 5 章会学的 while true 无限循环加 break 跳出。
>> n = getnumber('Please enter a number')Please enter a number: helloNot a number, try againPlease enter a number: tNot a number, try againPlease enter a number: 42n = 42
try x = input('Enter a number: '); y = sqrt(x); fprintf('sqrt is %.2f\n', y)catch disp('Something went wrong; using default value 0') y = 0;end
try/catch 本质上是一种自动错误检测版的 if-else——只要 try 体里抛了任何 error,就跳到 catch 体执行。教材原话是「may be a bit complicated to understand at this point, but keep them in mind for the future」,意思是「现在不懂没关系,第 6 章还会回来」。
% 文件:flowcompare.mA1 = input('Enter area at point 1 (sq ft): ');A2 = input('Enter area at point 2 (sq ft): ');if A1 > A2 disp('Velocity at point 2 increases')elseif A1 < A2 disp('Velocity at point 2 decreases')else disp('Velocity at point 2 remains the same')end
物理直觉:管子越细,水流越快——A1 更大 → A2 更细 → 速度上升。
例 3:判定数字奇偶
最简单但最能体现「理解 if 含义」的练习:随机生成一个整数,判断奇偶。
n = randi([1, 100]); % [1, 100] 的随机整数if rem(n, 2) == 0 % rem = remainder(余数) fprintf('%d is even\n', n)else fprintf('%d is odd\n', n)end