如何妥善保留println调试代码?
Great question—dealing with leftover debug prints is such a common annoyance, especially for small scripts where setting up a full test suite feels overkill. Your two-file approach works, but there are cleaner ways to keep your debug work without duplicating code or adding heavy tools. Here are a few Scala-specific solutions tailored to your use case:
1. Custom Debug Toggle (Simplest for Small Programs)
Create a tiny utility object to wrap your debug prints, so you can flip a single switch to enable/disable all debug output. This avoids cluttering your code with repeated conditionals and keeps your debug logic centralized.
Here's how to adapt your code:
import java.io.PrintWriter import scala.collection.mutable.ListBuffer import scala.collection.mutable.{Set => MutSet} import scala.collection.mutable.{Map => MutableMap} import scala.collection.mutable.{ListBuffer} // Add this debug utility at the top object Debug { var enabled: Boolean = false // Flip this to true/false to toggle debug def println(msg: => String): Unit = { if (enabled) scala.Predef.println(msg) } } object Solution { /** @TODO "Sherlock and the Valid String", Strings */ // Complete the isValid function below. def isValid(s: String): String = { // Count frequencies var freqmap = Map[Char, Int]() var old = 0 for (c <- s) { old = freqmap.getOrElse(c, 0) + 1 freqmap = freqmap + (c -> old) } // Replace println with Debug.println Debug.println(s"Counts of characters in string:\n" + freqmap.mkString(", \n")) // Check if problems or okay var oneDeviation = false var initFreq = freqmap(s(0)) val allowedFreqs = ListBuffer(initFreq) val counter = MutableMap[Int, Int](initFreq -> 1) var isFreqOne = false var freqThatIsOne: FreqIsOne = None Debug.println(s"Init freq: $initFreq") Debug.println(s"counter: " + counter.mkString(", \n")) Debug.println() for (freq <- freqmap.values) { Debug.println("------------------") Debug.println(s"Freq: $freq") if (!oneDeviation) { if (freq != initFreq) { oneDeviation = true // greater than 1 diff and no freq is 1 , eg 2 and 4 // if pass this we know diff is 1 if (isBiggerThanOneDiffAndNoOneFreq(initFreq, freq)) { return "NO" } // check if we have a freq that is one if (initFreq == 1 || freq == 1) { // one freq which is 1 if (initFreq == 1) { isFreqOne = true freqThatIsOne = Init // only freq allowed allowedFreqs.remove(0) allowedFreqs += freq } else if (freq == 1) { isFreqOne = true freqThatIsOne = Freq // only allowed is initFreq } // one diff but larger than 1 freqs, only allowed // is the lower frequency } else { if (freq > initFreq) { allowedFreqs.remove(0) allowedFreqs += freq } } // no new freq } else { } } else { if (!allowedFreqs.contains(freq)) return "NO" } old = counter(initFreq) counter(initFreq) = old + 1 Debug.println(s"counter: " + counter.mkString(", ")) } "YES" } def isBiggerThanOneDiffAndNoOneFreq(initFreq: Int, freq: Int): Boolean = { math.abs(freq - initFreq) > 1 && (initFreq != 1 && freq != 1) } sealed trait FreqIsOne case object Init extends FreqIsOne case object Freq extends FreqIsOne case object None extends FreqIsOne def main(args: Array[String]) { val stdin = scala.io.StdIn val s = stdin.readLine // Enable debug here if needed // Debug.enabled = true val result = isValid(s) println(result) } }
Just uncomment Debug.enabled = true in main when you need to see debug output, and comment it out for clean production runs. No duplicate files needed!
2. Command-Line Toggle (No Code Changes Needed)
If you don't want to edit code to enable debug, use system properties to control output at runtime. Wrap your debug prints in a check for a system property:
// Replace your println calls with this: if (sys.props.getOrElse("debug", "false").toBoolean) { println(s"Counts of characters in string:\n" + freqmap.mkString(", \n")) }
Then run your program with debug enabled like this:
scala -Ddebug=true Solution.scala
And run normally without the -Ddebug=true flag to suppress output. This is great for quick debugging without touching your code.
3. Lightweight Logging (More Flexible for Growth)
If you want to scale beyond simple prints (like different debug levels), use a minimal logging library like slf4j-simple—no complex configuration required.
First, add the dependency (if using sbt, add to build.sbt):
libraryDependencies += "org.slf4j" % "slf4j-simple" % "2.0.9"
Then replace your println calls with debug logs:
import org.slf4j.LoggerFactory object Solution { private val logger = LoggerFactory.getLogger(getClass) def isValid(s: String): String = { // ... your code ... logger.debug(s"Counts of characters in string:\n${freqmap.mkString(", \n")}") // ... rest of your code ... } }
By default, debug logs are hidden. To enable them, set the log level via system property:
scala -Dorg.slf4j.simpleLogger.defaultLogLevel=debug Solution.scala
This gives you more control (info, warn, error levels) if your program grows, without the overhead of a full test framework.
Why Your Two-File Approach Isn't Ideal
Keeping separate debug and clean versions works, but it's easy to forget to sync changes between the two files (e.g., fixing a bug in one but not the other). The above solutions let you keep a single codebase while retaining all your debug work.
内容的提问来源于stack exchange,提问作者Databogdan

