scala console println源码分析
原理
这段源码定义了一个名为Console
的对象,它提供了在终端上打印和读取值的功能。
在源码中,Console
对象使用了DynamicVariable
类来保存默认的输出流、错误流和输入流。DynamicVariable
是Scala标准库提供的一种机制,用于创建线程本地变量。通过使用DynamicVariable
,Console
对象可以为不同的线程设置独立的输出流、错误流和输入流,而不会相互干扰。
Console
对象提供了一系列方法来操作默认的输出流、错误流和输入流。例如,setOutDirect
、setErrDirect
和setInDirect
方法用于直接设置默认的输出流、错误流和输入流。withOut
、withErr
和withIn
方法则允许在执行指定的代码块期间临时更改默认的输出流、错误流和输入流,以便进行特定的操作。
除了操作流之外,Console
对象还提供了一些打印和读取值的方法。例如,print
方法用于将对象以字符串形式打印到默认的输出流,println
方法在默认输出流上打印一个换行字符,printf
方法用于格式化打印字符串。另外,readLine
方法用于从默认输入流中读取一行文本,readBoolean
、readByte
、readChar
等方法用于从默认输入流中读取不同类型的值。
通过使用Console
对象,开发人员可以方便地在终端上进行输入和输出操作,并且可以根据需要灵活地切换默认的输出流、错误流和输入流。这对于开发命令行应用程序或与用户进行交互的程序非常有用。
方法总结
方法 | 描述 |
---|---|
setOutDirect(out) | 设置默认输出流为指定的PrintStream对象。 |
setErrDirect(err) | 设置默认错误流为指定的PrintStream对象。 |
setInDirect(in) | 设置默认输入流为指定的BufferedReader对象。 |
out | 获取当前默认的输出流。 |
err | 获取当前默认的错误流。 |
in | 获取当前默认的输入流。 |
withOutT(thunk) | 在执行给定的代码块期间,将默认输出流更改为指定的PrintStream对象,并返回代码块的结果。 |
withOutT(thunk) | 在执行给定的代码块期间,将默认输出流更改为通过给定的OutputStream对象创建的PrintStream对象,并返回代码块的结果。 |
withErrT(thunk) | 在执行给定的代码块期间,将默认错误流更改为指定的PrintStream对象,并返回代码块的结果。 |
withErrT(thunk) | 在执行给定的代码块期间,将默认错误流更改为通过给定的OutputStream对象创建的PrintStream对象,并返回代码块的结果。 |
withInT(thunk) | 在执行给定的代码块期间,将默认输入流更改为指定的Reader对象,并返回代码块的结果。 |
withInT(thunk) | 在执行给定的代码块期间,将默认输入流更改为通过给定的InputStream对象创建的Reader对象,并返回代码块的结果。 |
print(obj) | 将指定的对象使用其toString方法打印到默认输出流。如果对象为null,则打印字符串"null"。 |
flush() | 刷新输出流。在需要将部分输出(即未以换行符结束的输出)显示在终端上时,需要调用此方法。 |
println() | 在默认输出流中打印一个换行符。 |
println(x) | 在默认输出流中打印一个对象,后跟一个换行符。 |
printf(text, args) | 根据指定的格式字符串(类似于C语言中的printf函数),将参数作为格式化字符串打印到默认输出流中。格式字符串的解释可以参考java.util.Formatter的文档。参数args是要填充格式字符串的值。如果格式字符串或参数存在问题,则抛出IllegalArgumentException异常。 |
示例
// 设置默认输出流为指定的PrintStream对象
Console.setOutDirect(System.out)
// 设置默认错误流为指定的PrintStream对象
Console.setErrDirect(System.err)
// 设置默认输入流为指定的BufferedReader对象
val reader = new BufferedReader(new InputStreamReader(System.in))
Console.setInDirect(reader)
// 获取当前默认的输出流
val outStream = Console.out
// 获取当前默认的错误流
val errStream = Console.err
// 获取当前默认的输入流
val inputStream = Console.in
// 在执行给定的代码块期间,将默认输出流更改为指定的PrintStream对象,并返回代码块的结果
val result1 = Console.withOut(System.out) {
println("This is printed to the specified output stream")
"Result of the code block"
}
// 在执行给定的代码块期间,将默认输出流更改为通过给定的OutputStream对象创建的PrintStream对象,并返回代码块的结果
val result2 = Console.withOut(System.out) {
println("This is printed to the specified output stream")
"Result of the code block"
}
// 在执行给定的代码块期间,将默认错误流更改为指定的PrintStream对象,并返回代码块的结果
val result3 = Console.withErr(System.err) {
println("This is printed to the specified error stream")
"Result of the code block"
}
// 在执行给定的代码块期间,将默认错误流更改为通过给定的OutputStream对象创建的PrintStream对象,并返回代码块的结果
val result4 = Console.withErr(System.err) {
println("This is printed to the specified error stream")
"Result of the code block"
}
// 在执行给定的代码块期间,将默认输入流更改为指定的Reader对象,并返回代码块的结果
val result5 = Console.withIn(new FileReader("file.txt")) {
val line = Console.in.readLine()
println(s"Read from the specified input stream: $line")
"Result of the code block"
}
// 在执行给定的代码块期间,将默认输入流更改为通过给定的InputStream对象创建的Reader对象,并返回代码块的结果
val result6 = Console.withIn(new FileInputStream("file.txt")) {
val line = Console.in.readLine()
println(s"Read from the specified input stream: $line")
"Result of the code block"
}
// 将指定的对象使用其toString方法打印到默认输出流
Console.print("Hello, World!")
// 刷新输出流
Console.flush()
// 在默认输出流中打印一个换行符
Console.println()
// 在默认输出流中打印一个对象,后跟一个换行符
Console.println("Hello, World!")
// 根据指定的格式字符串,将参数作为格式化字符串打印到默认输出流中
Console.printf("Name: %s, Age: %d", "John Doe", 25)
注意:以上示例代码仅用于演示每个方法的使用方式,并非可运行代码。
中文源码
/**
* 实现在终端上打印Scala值以及读取特定值的功能。
* 还定义了用于在ANSI终端上标记文本的常量。
*
* 作者:Matthias Zenger
* 版本:1.0,03/09/2003
*/
object Console extends DeprecatedConsole with AnsiColor {
private val outVar = new DynamicVariable[PrintStream](java.lang.System.out)
private val errVar = new DynamicVariable[PrintStream](java.lang.System.err)
private val inVar = new DynamicVariable[BufferedReader](
new BufferedReader(new InputStreamReader(java.lang.System.in)))
protected def setOutDirect(out: PrintStream): Unit = outVar.value = out
protected def setErrDirect(err: PrintStream): Unit = errVar.value = err
protected def setInDirect(in: BufferedReader): Unit = inVar.value = in
/** 默认的输出流,可以通过`setOut`进行覆盖 */
def out = outVar.value
/** 默认的错误流,可以通过`setErr`进行覆盖 */
def err = errVar.value
/** 默认的输入流,可以通过`setIn`进行覆盖 */
def in = inVar.value
/** 在执行一个thunk期间设置默认的输出流。
*
* @example {{{
* withOut(Console.err) { println("This goes to default _error_") }
* }}}
*
* @param out 新的输出流
* @param thunk 使用新的输出流执行的代码块
* @return `thunk`的结果
* @see `withOut[T](out:OutputStream)(thunk: => T)`
*/
def withOut[T](out: PrintStream)(thunk: =>T): T =
outVar.withValue(out)(thunk)
/** 在执行一个thunk期间设置默认的输出流。
*
* @param out 新的输出流
* @param thunk 使用新的输出流执行的代码块
* @return `thunk`的结果
* @see `withOut[T](out:PrintStream)(thunk: => T)`
*/
def withOut[T](out: OutputStream)(thunk: =>T): T =
withOut(new PrintStream(out))(thunk)
/** 在执行一个thunk期间设置默认的错误流。
* @example {{{
* withErr(Console.out) { println("This goes to default _out_") }
* }}}
*
* @param err 新的错误流
* @param thunk 使用新的错误流执行的代码块
* @return `thunk`的结果
* @see `withErr[T](err:OutputStream)(thunk: =>T)`
*/
def withErr[T](err: PrintStream)(thunk: =>T): T =
errVar.withValue(err)(thunk)
/** 在执行一个thunk期间设置默认的错误流。
*
* @param err 新的错误流
* @param thunk 使用新的错误流执行的代码块
* @return `thunk`的结果
* @see `withErr[T](err:PrintStream)(thunk: =>T)`
*/
def withErr[T](err: OutputStream)(thunk: =>T): T =
withErr(new PrintStream(err))(thunk)
/** 在执行一个thunk期间设置默认的输入流。
*
* @example {{{
* val someFile:Reader = openFile("file.txt")
* withIn(someFile) {
* // 从file.txt中读取一行,而不是默认的输入流
* println(readLine)
* }
* }}}
*
* @param reader 使用新的输入流执行的代码块
*
* @return `thunk`的结果
* @see `withIn[T](in:InputStream)(thunk: =>T)`
*/
def withIn[T](reader: Reader)(thunk: =>T): T =
inVar.withValue(new BufferedReader(reader))(thunk)
```scala
/** 设置默认的输入流,在执行一个thunk期间使用该输入流。
*
* @param in 新的输入流。
* @param thunk 使用新的输入流执行的代码块。
* @return `thunk`的结果。
* @see `withIn[T](reader:Reader)(thunk: =>T)`
*/
def withIn[T](in: InputStream)(thunk: =>T): T =
withIn(new InputStreamReader(in))(thunk)
/** 使用对象的`toString`方法将对象打印到`out`流中。
*
* @param obj 要打印的对象,可以为null。
*/
def print(obj: Any) {
out.print(if (null == obj) "null" else obj.toString())
}
/** 刷新输出流。当需要在终端上显示部分输出(即未以换行符结尾的输出)时,需要使用此函数。
*/
def flush() { out.flush() }
/** 在默认输出流中打印一个换行字符。
*/
def println() { out.println() }
/** 将对象打印到默认输出流中,后面跟着一个换行字符。
*
* @param x 要打印的对象。
*/
def println(x: Any) { out.println(x) }
/** 根据字符串模式(类似于C语言中的printf函数),将参数作为格式化字符串打印到默认输出流中。
*
* 格式化模式的解释请参见`java.util.Formatter`。
*
* @param text 格式化模式的字符串。
* @param args 实例化模式的参数。
* @throws java.lang.IllegalArgumentException 如果格式字符串或参数有问题。
*/
def printf(text: String, args: Any*) { out.print(text format (args : _*)) }
}
private[scala] abstract class DeprecatedConsole {
self: Console.type =>
/** 仅供内部使用。 */
protected def setOutDirect(out: PrintStream): Unit
protected def setErrDirect(err: PrintStream): Unit
protected def setInDirect(in: BufferedReader): Unit
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readBoolean(): Boolean = StdIn.readBoolean()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readByte(): Byte = StdIn.readByte()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readChar(): Char = StdIn.readChar()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readDouble(): Double = StdIn.readDouble()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readFloat(): Float = StdIn.readFloat()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readInt(): Int = StdIn.readInt()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readLine(): String = StdIn.readLine()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readLine(text: String, args: Any*): String = StdIn.readLine(text, args: _*)
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readLong(): Long = StdIn.readLong()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readShort(): Short = StdIn.readShort()
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readf(format: String): List[Any] = StdIn.readf(format)
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readf1(format: String): Any = StdIn.readf1(format)
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readf2(format: String): (Any, Any) = StdIn.readf2(format)
@deprecated("请使用scala.io.StdIn中的方法", "2.11.0") def readf3(format: String): (Any, Any, Any) = StdIn.readf3(format)
/** 设置默认的输出流。
*
* @param out 新的输出流。
*/
@deprecated("请使用withOut", "2.11.0") def setOut(out: PrintStream): Unit = setOutDirect(out)
/** 设置默认的输出流。
*
* @param out 新的输出流。
*/
@deprecated("请使用withOut", "2.11.0") def setOut(out: OutputStream): Unit = setOutDirect(new PrintStream(out))
/** 设置默认的错误流。
*
* @param err 新的错误流。
*/
@deprecated("请使用withErr", "2.11.0") def setErr(err: PrintStream): Unit = setErrDirect(err)
/** 设置默认的错误流。
*
* @param err 新的错误流。
*/
@deprecated("请使用withErr", "2.11.0") def setErr(err: OutputStream): Unit = setErrDirect(new PrintStream(err))
/** 设置默认的输入流。
*
* @param reader 指定新的输入流。
*/
@deprecated("请使用withIn", "2.11.0") def setIn(reader: Reader): Unit = setInDirect(new BufferedReader(reader))
/** 设置默认的输入流。
*
* @param in 新的输入流。
*/
@deprecated("请使用withIn", "2.11.0") def setIn(in: InputStream): Unit = setInDirect(new BufferedReader(new InputStreamReader(in)))
}