在做网络监控系统的时候,经常需要写一些工具函数来处理数据。比如从一段日志里提取出状态码和响应时间,理想情况下一个函数能同时把这两个值返回,用起来才顺手。但Scala不像某些语言直接支持多返回值,得换个思路来实现。
用元组(Tuple)最直接
最常见的方式就是让函数返回一个元组。比如写个解析日志的方法:
def parseLog(line: String): (Int, Long) = {
val parts = line.split(" ")
val code = parts(0).toInt
val time = parts(1).toLong
(code, time)
}
调用的时候可以直接解构:
val (statusCode, responseTime) = parseLog("200 150")
println(s"状态码:$statusCode,耗时:$responseTime ms")
这样一行日志的信息就轻松拆开了,写监控脚本时特别方便。
用样例类更清晰
如果返回的值多了,比如除了状态码、耗时,还要返回IP和路径,元组就容易搞混。这时候定义个样例类更靠谱:
case class LogInfo(code: Int, time: Long, ip: String, path: String)
def parseFullLog(line: String): LogInfo = {
val parts = line.split(" ")
LogInfo(parts(0).toInt, parts(1).toLong, parts(2), parts(3))
}
调用后可以直接用点号访问字段,代码读起来更像日常说话:
val info = parseFullLog("404 200 192.168.1.100 /api/user")
if (info.code == 404) alertUser(info.ip)
实际场景中的小应用
我们公司有个小脚本每天扫一遍访问日志,统计异常请求。以前是分开写两个函数,一个取状态码,一个取时间,调用时要重复解析字符串,效率低还容易出错。改成元组返回之后,一次解析全搞定,代码干净了不少。
有时候偷懒不想定义类,又怕元组记不清顺序,可以加个别名:
type CheckResult = (Boolean, String)
def checkServer(url: String): CheckResult = {
// 模拟检测
if (url.contains("down")) (false, "服务不可用")
else (true, "正常")
}
这样别人看代码也知道返回的是“是否正常”和“提示信息”,不会搞反。
这些方法看着简单,但在写监控工具这种小而频繁的任务里,省下的功夫可不少。关键是选对场景:两三个值用元组,复杂结构上样例类,别死守一种套路就行。