2

所以昨天我有一个日志文件,它在提供的 log.txt 中有逗号分隔的条目,如下所示:

entry1.1,entry1.2,entry1.3
entry2.1,entry2,2,entry2.3
..........................

因此,我非常高兴地继续创建了一个案例类:

case class LogEntry(
  entry1:String,
  entry2:String,
  entry3:String
)

并在阅读案例类时填充案例类,如下所示:

line.split match {
  case Array(entry1,entry2,entry3) => LogEntry(entry1,entry2,entry3)
}

现在当我今天运行我的代码时出现了问题,我注意到没有创建 LogEntry 对象。

我查看了今天提供给我的 log.txt 并意识到条目已更改:

我现在有:

entry1.1,entry1.2,entry1.3,entry1.4
entry2.1,entry2,2,entry2.3,entry2.4
...................................

我现在在每一行中都有第四个条目。好吧,似乎没什么大不了的,只需使用第四个条目(代码气味 1)更改我的案例类,然后更改模式匹配(代码气味 2)

有人可以建议我应该如何编写代码来处理这种情况。我想扩展我的代码而不是修改它。

谢谢

4

1 回答 1

2

当您想要正确抽象日志行时,要做的第一件事是为各个元素提供名称和适当的类型,而不是通过名称(即 entry1、entry2 等)提供伪索引。所以我们会有:

case class LogEntry(
    time: java.util.Date,
    userId: Int,
    host: String
)

输入的严格程度取决于您的确切用例(注意host这里不是 a java.net.InetAddress)。

将新列添加到日志文件时,您可能需要保留两件事:

  1. 期望旧式 LogEntries 的函数
  2. 即使添加了新功能,也会处理旧日志文件。

案例 1 很简单。只需将字段添加到案例类:

case class LogEntry(
    time: java.util.Date,
    userId: Int,
    host: String,
    port: Int
)

由于您有名称,您甚至可以更改字段的顺序,并且旧代码仍然可以正常工作,因为它期望的字段仍然存在。由于您不想再处理旧的日志文件,只需调整读入的代码。

情况 2 有点棘手:您必须反映这样一个事实,即您正在运行的应用程序中会有新旧日志条目。您可以:

  1. 使附加字段可选并提供默认值:

    case class LogEntry(
        time: java.util.Date,
        userId: Int,
        host: String,
        port: Option[Int] = None
    ) 
    
  2. 在层次结构中反映日志格式的版本(注意:您不应该从案例类继承,因此您必须从中创建普通类):

    class LogEntry(
        val time: java.util.Date,
        val userId: Int,
        val host: String
    )
    
    class ExtendedLogEntry(
        time: java.util.Date,
        userId: Int,
        host: String,
        val port: Int
    ) extends LogEntry(time, userId, host)
    

选项 1 让处理日志条目的代码处理条目类型之间的差异(即所有函数仍然是 type LogEntry => ?)。进一步还要注意,它可能允许不一致的日志条目(添加两个字段,格式 1 中都不存在,格式 2 中需要,您仍然可以将其中一个设置为None)。

Option 2 lets the calling code handle the difference between the entry types. If an advanced function needs an ExtendedLogEntry, it's type will be ExtendedLogEntry => _, so you cannot supply a LogEntry to that function (alternative: pattern match in the function and provide default / fallback behavior). Further, it prevents the inconsistency that can occur with option 1.

Concerning read-in: Option 1 will automatically set the default argument when reading old-style log files, in Option 2, old-style log files will result in LogEntry as before. So in both cases, old read-in code does not need to be changed, but potentially adapted in order to detect new-style or old-style logs and produce appropriate entries. (Note that this is potentially a problem with Option 2 as the style of the log is statically enforced through the typing system if you do not want to cast).

于 2013-04-15T21:15:13.097 回答