はじめに
この記事で伝えたいことは、「Xcode環境でAtCoderの解答コードをテストするときに、stderr(標準エラー出力)に出力することによる副次的な効果について」です。
1. stderrへの出力方法
ご存知の方が大半でしょうが、まず、Swiftにてstderrへ出力する方法を説明します。
私は普段、下記のメソッドを使用しています。
func printErr(_ str: String, terminator: String = "\n") {
let string = str + terminator
FileHandle.standardError.write(string.data(using: .utf8)!)
FileHandle.standardError.synchronizeFile()
}
引数は文字列と区切り文字です。文字列を一つしか指定できませんので、文字列補間(やString:format:)で一つの文字列にして渡します。区切り文字のデフォルトは改行
。
2. 最初にstderrに出力する
AtCoderのプログラムでは、入力情報を標準入力(stdin)から読み込むことから始めるのが普通だと思いますが、その前にstderrにReady!(例)を出力します。
これによる副次的効果としては、次の2点。
2.1 副次的効果(その一):コンソールが自動的に開く
Xcodeにてプログラムを実行するには⌘R
(command+R)、実行中のプログラムを中止するには⌘.
(command+period)のショートカットで操作します(もしくはメニュー操作で)。
実行したプログラムが標準入力からの入力を待っている場合、Xcodeのコンソールを開いて入力を与えるのですが、前回⌘.
でプログラムを中断した場合、コンソールが閉じてしまっているので、⇧⌘C
(shift+command+C)で再びコンソールを開いてやる必要があり、これが不便でした。
しかし、最初にstderrに出力することによって、コンソールが自動的に開きstderrの情報が出力されるようになります。
この挙動をつい最近発見して「これまでの無駄は何だったのだろう!」と思うほど便利になりました。
例として、3つの整数A,B,Cを入力し$A+B*C$の結果を出力するプログラムは以下のようなコードになります。
printErr("Ready!")
let (a, b, c) = listOfInt().toTupple()
let ans = a + b * c
print(ans)
listOfInt()やtoTupple()は、巻末の参考記事をご参照ください。
2.2 副次的効果(その二):入力待ちのタイミングが分かる
最初にstderrに出力することで、ビルドが完了しプログラムが起動され入力待ちになったタイミングが分かるようになりました。こう書くと当然のことなんですが・・・。
コンソールが開いているときにstderrに出力しない場合は、この入力待ちのタイミングが分からず、コンソールに入力情報を⌘V
(command+V:貼り付け)しても結果が出ずやり直すことがありました(やり直しは⌘.
して⌘R
)。つまりプログラムが起動されてもまだ入力待ちになっていないタイミングで⌘V
してもコンソールには貼り付いてもプログラムの入力には渡っておらず、入力を待ち続けるので結果が出てこない訳です。簡単にいうと⌘R
後の⌘V
が早すぎたということです。(コンソールが閉じている場合は、コンソールを⇧⌘C
で開いてから⌘V
と操作するのでタイミングのずれは起きにくい)
いまは**Ready!**と出たら⌘V
すれば良いので、このずれをまったく気にする必要がなくなりました。
3. stderrはAtCoderのオンラインジャッジに影響しない
ループ途中の変数情報などをstderrに出力してもACが取れます。これは、副次的効果ではありませんが、事実としてそういうことです。stderrの内容は関係なく、stdoutの内容だけを判定していると思われます。
もちろん、stderrに大量の情報を出力すると、それは実行時間に影響しTLEになる可能性があるので、AtCoderに提出するコードではデバック情報の出力などはコメントアウトしておくのが無難です。
おわりに
ちょっとしたことですが、AtCoderのコンテスト中は時間との戦いですので、無駄なことは極力省きたいと思うのが普通。今回の記事の内容で、これまで不便だったことが改善され快適な環境になりました。
同じような環境で使われている方の参考になれば幸いです。
参考記事
以上