- 发生时间:2022-04-24
- 问题描述:在调试某个项目的功能测试工控板与上位机的通信时,修改上位机的 isDebugMode 参数为 true 后,工控板报错,不会进入自动检测。
- 问题类别:软件开发
- 原因分析:
- 在 JavaScript 代码中误用 keyword arguments 的方式来传参,即
isDebugMode=true,而 JavaScript 并不支持这一语法,会导致本该赋给 isDebugMode 的值误赋给configPath,进而导致配置文件路径有误。 - 因此,当工控板向上位机请求配置文件时,上位机无法响应,导致工控板报错。(详见下文「原因分析详解」)
- 在 JavaScript 代码中误用 keyword arguments 的方式来传参,即
- 解决方案:取消 keyword arguments 的传参方式,改用 positional arguments 的传参方式。
- 实施结果:修改后工控板可以正常收到配置文件,并继续后面的自动检测了。
- 经验总结:
- Python 支持 keyword arguments 语法,但 JavaScript、Golang 和 C/C++ 等语言都不支持,函数传参时要注意这一点。
- 不同编程语言的语法是有差异的。平时开发调试时,遇到这些不同点,特别是容易踩坑的地方,应该及时归纳总结,举一反三。
原因分析详解
上位机定义了客户端类 Client ,用来跟工控板通信,这个类的构造函数签名如下:
constructor(serialport, configPath = DefaultConfigPath, isDebugMode = false) {}
出现问题时,创建客户端的代码如下:
client = new Client(serialport, isDebugMode = true);
问题在于,JavaScript 并不支持 keyword arguments 的语法,因此以上代码的实际效果是:
isDebugMode 的取值实际上是赋给 YunganClient 的第二个参数 configPath,
因此 configPath 的值为 true,自然无法读取配置文件,并引发后面的通信异常错误。
keyword arguments 语法简介
Python 官方术语表 的「argument」术语对「keyword argument」(「关键字参数」)和「positional argument」(「位置参数」)进行了介绍:
Argument: A value passed to a function (or method) when calling the function. There are two kinds of argument:
-
keyword argument: an argument preceded by an identifier (e.g.
name=) in a function call or passed as a value in a dictionary preceded by**. For example, 3 and 5 are both keyword arguments in the following calls to complex():complex(real=3, imag=5) complex(**{'real': 3, 'imag': 5}) -
positional argument: an argument that is not a keyword argument. Positional arguments can appear at the beginning of an argument list and/or be passed as elements of an iterable preceded by
*. For example, 3 and 5 are both positional arguments in the following calls:complex(3, 5) complex(*(3, 5))
不同语言对 keyword arguments 的支持情况
最后我们来调查一些常见语言对 keyword arguments 的支持情况吧。 我们统一定义一个简单的函数,其功能是打印某个人的名字、地址和年龄。
Python:支持 keyword arguments
def show_person(name, addr="Beijing", age=18):
print(f'name={name}, addr={addr}, age={age}')
# 打印结果符合预期: name=guojing, addr=Beijing, age=20
show_person('guojing', age=20)
JavaScript:不支持 keyword arguments,误用大概率会出现参数被错误赋值的问题
function show_person(name, addr='Beijing', age=18) {
console.log(`name=${name}, addr=${addr}, age=${age}`)
}
// 打印结果不符合预期: name=guojing, addr=20, age=18
show_person('guojing', age=20)
C++:不支持 keyword arguments,编译会报错
#include <iostream>
#include <string>
using namespace std;
void show_person(string name, string addr = "Beijing", int age = 18) {
std::cout << "name: " << name << ", addr: " << addr << ", age" << age
<< std::endl;
}
int main() {
show_person("guojing", age = 20);
}
编译以上代码会报错:
along:~/src/default-arguments$ g++ default_argument.cpp
default_argument.cpp: In function ‘int main()’:
default_argument.cpp:12:26: error: ‘age’ was not declared in this scope
12 | show_person("guojing", age = 20);
|
Golang:不支持 keyword arguments,编译会报错
package main
import "fmt"
func showPeople(name string, addr string, age int) {
fmt.Printf("name: %s, addr: %s, age: %d\n", name, addr, age)
}
func main() {
showPeople("guojing", age = 20)
}
编译以上代码会报错:
along:~/src/default-arguments$ go build default_argument.go
# command-line-arguments
./default_argument.go:10:28: syntax error: unexpected =, expecting comma or )
另外,特别注意:Golang 也不支持默认函数参数!