英文:
Kotlin Koans Operators Overloading
问题
我用以下代码编写了一个单独的项目,我觉得程序表现如我所预期。
为什么不能通过Kotlin Koans测试写这个呢?
import TimeInterval.*
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int)
// 可添加到日期的支持的时间间隔:
enum class TimeInterval(var n: Int = 1) {
DAY, WEEK, YEAR
}
operator fun TimeInterval.times(times: Int): TimeInterval {
n *= times
return this
}
operator fun MyDate.plus(timeInterval: TimeInterval): MyDate =
addTimeIntervals(timeInterval, timeInterval.n)
英文:
I wrote a separate project with the following code, and I feel that the program performs as I expected.
Why can't this write through the Kotlin Koans test?
import TimeInterval.*
data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int)
// Supported intervals that might be added to dates:
enum class TimeInterval(var n: Int = 1) {
DAY, WEEK, YEAR
}
operator fun TimeInterval.times(times: Int): TimeInterval {
n *= times
return this
}
operator fun MyDate.plus(timeInterval: TimeInterval): MyDate =
addTimeIntervals(timeInterval, timeInterval.n)
答案1
得分: 1
这并不是你所想的意思:
enum class TimeInterval(var n: Int = 1) {
DAY, WEEK, YEAR
}
这声明了3个枚举常量 - DAY
、WEEK
和 YEAR
。每个常量都有自己的 n
属性,初始值为1。你可以将其理解为:
data class TimeInterval private constructor(var n: Int = 1) {
companion object {
val DAY = TimeInterval()
val WEEK = TimeInterval()
val YEAR = TimeInterval()
}
}
关键是,只有3个 TimeInterval
的实例,没有其他的。每次访问 DAY
时,都不会获得全新的实例。
因此,当你执行 n *= times
时,你正在改变该 TimeInterval
实例的 n
值,这个更改会持续影响下一次使用该实例。例如:
val fiveDays = DAY * 5 // 这将设置 DAY.n 为 1 * 5 = 5
val twoDays = DAY * 2 // 这将设置 DAY.n 为 5 * 2 = 10
// 这两者都会打印出 10!
println(fiveDays.n)
println(twoDays.n)
因此,在枚举类的构造函数中使用 var
或任何可变的东西可能会导致一些非常令人困惑的行为,几乎从不是你想要的。
当然,如果你不会多次使用任何 TimeInterval
实例,你可能不会注意到这一点。但是 Koan 上的测试确实会多次使用它们。
你应该使用一些能够组合 TimeInterval
和一个数字的东西。你可以使用 Pair<TimeInterval, Int>
,或者更好的是,按照 Koan 中的提示,编写一个新的类。
英文:
This does not mean what you think it does:
enum class TimeInterval(var n: Int = 1) {
DAY, WEEK, YEAR
}
This declares 3 enum constants - DAY
, WEEK
and YEAR
. Each constant has its own n
property, initially set to 1. You can think of this as:
data class TimeInterval private constructor(var n: Int = 1) {
companion object {
val DAY = TimeInterval()
val WEEK = TimeInterval()
val YEAR = TimeInterval()
}
}
Crucially, there are only 3 instances of TimeInterval
, period. You don't get a brand new instance every time you access DAY
for example.
Therefore, when you do n *= times
, you are changing the value of n
for that instance of TimeInterval
, and this change persists the next time you use that instance. e.g.
val fiveDays = DAY * 5 // this sets DAY.n to 1 * 5 = 5
val twoDays = DAY * 2 // this sets DAY.n to 5 * 2 = 10
// both of these will print 10!
println(fiveDays.n)
println(twoDays.n)
Therefore, using var
s, or anything mutable in enum class' constructors can cause some very confusing behaviours, and is almost never what you want.
Of course, you don't notice this if you don't use any instance of TimeInterval
more than once. But the tests on the Koan do use them more than once.
You should use something that composes a TimeInterval
and a number. You can use a Pair<TimeInterval, Int>
, or better, write a new class, as the hint in the Koan says.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论