最后由 麻爪 于 2026-10-16 13:35 编辑
二、函数调用的基本形式
按照函数调用在代码中的角色和使用场景,可以把函数调用划分为四种形式。需要明确的是,传入参数、启动函数的功能没有什么不同,只是写法和具体用途有些区别,我们需要加以区分。
(一)过程式调用
形式:独立语句
语法格式:函数名(实参列表); 结尾必须加分号,作为一条独立的执行语句。
核心定位:只触发函数执行动作,不关心、不使用其返回值(不是说该函数就没有返回值);比如打印日志、发送订单、关闭文件、释放资源等纯动作类场景。这是最基础的调用形式,无返回值(`void`类型)的函数只能用这种方式调用。
举例: // 1. 打印函数,无返回值,只能这么用
Print("当前收盘价:", Close[0]);
// 2. 下单函数,有返回值,但只关心动作、忽略结果
OrderSend(request, result); // 只执行下单动作,不判断返回是否成功
// 3. 文件关闭函数,纯操作类函数
FileClose(fileHandle); // 只执行关闭文件的动作
(二)结果输出式调用
形式:给某个变量赋值
语法格式:返回值类型 变量名 = 函数名(实参列表); 也可以先声明变量,后续再赋值;接收结果的变量类型,要和函数返回值类型兼容;
核心定位:把函数的返回值赋值给变量,保存下来后续多次使用;是获取计算结果的标准形式;这种形式调用的函数一定要有个明确的返回值;这种函数调用形式是最经典也是最常用的形式,因为本质上函数的结果也就是返回值,就是给别处使用的。
举例: // 计算止损价,存起来后面开仓、风控都要用
double stopPrice = CalcStopLoss(Close[0], 20, true);
// 获取K线总数,后面遍历循环要用
int totalBars = Bars(_Symbol, _Period);
// 计算组合夏普比率,后面优化对比要用
double sharpe = CalcSharpe(weight, returns, covMatrix);
(三)内嵌运算式调用
形式:函数调用直接作为表达式的一部分,参与条件判断、算术运算,不用先赋值给中间变量
语法格式:直接把函数调用写在表达式里,和常量、变量的地位完全一样。
核心定位:本质是利用了「函数调用本身就是一个有值的表达式」这个特性;如果某函数需要多处调用,那建议按结果输出调用模式,先设计一个变量,用该函数进行赋值,但如果某函数只有一处调用,没必要再做个中间变量去折腾,直接使用函数内嵌运算。
举例: // 1. 直接写在if条件里,不用先算好存变量
if(Close[0] < CalcStopLoss(entryPrice, 20, true))
{
OrderClose(ticket, lot, Close[0], 3, Red); // 触发止损平仓
}
// 2. 直接参与算术运算
double bodyPoint = MathAbs(Close[0] - Open[0]) / _Point;
(四)参数嵌套式调用
形式:把一个函数的返回值,直接作为另一个函数的实参传入
语法格式:外层函数名(内层函数名(实参列表), 其他实参);
核心定位:与内嵌运算式调用一样,此处同样是利用了「函数调用本身就是一个有值的表达式」这个特性;函数的实参可以是有具体返回值的表达式,所以有具体返回值的函数也可以当另一个函数的实参;这个作为实参的函数,它自己的实参其实也是外层函数的输入函数(在黑箱状态下,你可以这样认为),只不过这些实参先被传入内层函数,你可以把这个内层函数看作是该参数的预处理函数。
举例: // 先算K线实体大小,直接传给Print输出
Print("K线实体大小:", MathAbs(Close[0] - Open[0]) / _Point, "点");
// 先算均线值,直接参与价格判断
bool isTrendUp = Close[0] > iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
(五) 类型选用原则
1. 纯动作、无返回值的函数 → 直接用独立语句调用; 2. 结果后面还要多次用到 → 优先赋值调用存变量,清晰易调试; 3. 结果只用一次、逻辑简单 → 用表达式内调用或嵌套调用,代码更简洁; 4. 嵌套层数控制在 2 层以内,超过就拆成赋值调用,避免可读性崩盘。 |