LoginSignup
6
3

More than 5 years have passed since last update.

dump関数が超便利なので調べてみた

Last updated at Posted at 2017-11-30

この記事はyurue Advent Calendar1日目の投稿です!
AdventCalendar初めての投稿に加え、Qiitaの投稿初心者なので、わかりづらい部分があると思いますので、
その際はご指摘くださいm(_ _)m

Swiftには下記の標準出力関数が用意されています。
普段よく使うprint関数でも見慣れない引数があるのではないでしょうか。

public func print<Target>(_ items: Any..., separator: String = default, terminator: String = default, to output: inout Target) where Target : TextOutputStream
public func debugPrint<Target>(_ items: Any..., separator: String = default, terminator: String = default, to output: inout Target) where Target : TextOutputStream
public func dump<T>(_ value: T, name: String? = default, indent: Int = default, maxDepth: Int = default, maxItems: Int = default) -> T
public func dump<T, TargetStream>(_ value: T, to target: inout TargetStream, name: String? = default, indent: Int = default, maxDepth: Int = default, maxItems: Int = default) -> T where TargetStream : TextOutputStream

中でも今回は、変数の中身を詳細に出力することができるdump関数を紹介したいと思います。

引数

value: T

value には中身を確かめたい変数を入れます。
今回はできるだけ多くネストした変数として、重連結リストを利用します。

class Node {
    let key: Int
    var prev: Node?
    var next: Node?

    init(key: Int, prev: Node?, next: Node?) {
        self.key = key
        self.prev = prev
        self.next = next
    }
}

let n0 = Node(key: 1, prev: nil, next: nil)
let n1 = Node(key: 2, prev: n0, next: nil)
n0.next = n1
let n2 = Node(key: 3, prev: n1, next: n0)
n1.next = n2
n0.prev = n2

printで試しに出力してみると、中身が全然わかりませんね。

print(n0) //__lldb_expr_69.Node

ここで、dumpを使うと、かなり詳細に出力してくれます。

dump(n0)
/*
▿ __lldb_expr_69.Node #0
  - key: 1
  ▿ prev: Optional(__lldb_expr_69.Node)
    ▿ some: __lldb_expr_69.Node #1
      - key: 3
      ▿ prev: Optional(__lldb_expr_69.Node)
        ▿ some: __lldb_expr_69.Node #2
          - key: 2
          ▿ prev: Optional(__lldb_expr_69.Node)
            ▿ some: __lldb_expr_69.Node #0
          ▿ next: Optional(__lldb_expr_69.Node)
            ▿ some: __lldb_expr_69.Node #1
      ▿ next: Optional(__lldb_expr_69.Node)
        ▿ some: __lldb_expr_69.Node #0
  ▿ next: Optional(__lldb_expr_69.Node)
    ▿ some: __lldb_expr_69.Node #2
*/

to target: inout TargetStream

 where TargetStream : TextOutputStream 

とあるように、TargetStreamはTextOutputStream を継承したものである必要がありそうです。
TextOutputStream がわからなかったので調べてみました。公式リファレンス
リファレンスによるとTextOutputStreamはprotocolとして宣言されており、
String型, Substring型はこのprotocolに準拠しているそうです。

ということで、String型の値引数として関数に渡してみたいと思います。
inoutなので、C言語でいうポインタのように&をつけて渡すようです。

var stream: String = ""
dump(n0, to: &stream, name: "", indent: 5, maxDepth: 5, maxItems: 5)
dump(stream)

String型として宣言されたstreamに文字列が追加されていますね。

print(stream)
/*
     ▿ : __lldb_expr_113.Node #0
       - key: 1
       ▿ prev: Optional(__lldb_expr_113.Node)
         ▿ some: __lldb_expr_113.Node #1
           - key: 3
             (2 more children)
         (1 more child)
*/

試しにdumpでも同様にやってみましたが、改行は無視されるようです。

dump(stream)
// - "     ▿ : __lldb_expr_113.Node #0\n       - key: 1\n       ▿ prev: Optional(__lldb_expr_113.Node)\n         ▿ some: __lldb_expr_113.Node #1\n           - key: 3\n             (2 more children)\n         (1 more child)\n"

name: String? = default

行頭のクラス名の前にラベルを付けることができます。
ログが増えまくってきたときに使うと便利かも。

dump(n1, name: "hogehoge", indent: 5, maxDepth: 5, maxItems: 5)
/*
     ▿ hogehoge: __lldb_expr_36.Node #0
       - key: 2
       ▿ prev: Optional(__lldb_expr_36.Node)
         ▿ some: __lldb_expr_36.Node #1
           - key: 1
             (2 more children)
         (1 more child)

*/

試しにnilを入れてみてもnameを指定しない場合と変わらなかったのでdefaultはnilのようですね

dump(n1, name: nil, indent: 5, maxDepth: 5, maxItems: 5)
/*
     ▿ __lldb_expr_40.Node #0
       - key: 2
       ▿ prev: Optional(__lldb_expr_40.Node)
         ▿ some: __lldb_expr_40.Node #1
           - key: 1
             (2 more children)
         (1 more child)
*/

indent: Int = default

全体的なインデントの深さを変更できるみたいです。
各行のインデントが変えれればいいのに。
恐らくdefaultは0です。

dump(n1, name: nil, indent: 0, maxDepth: 5, maxItems: 5)
/*
▿ __lldb_expr_42.Node #0
  - key: 2
  ▿ prev: Optional(__lldb_expr_42.Node)
    ▿ some: __lldb_expr_42.Node #1
      - key: 1
        (2 more children)
    (1 more child)
*/

maxDepth: Int = default

どこまで追うかを決められます。

dump(n1, name: nil, indent: 0, maxDepth: 0, maxItems: 5) //▹ __lldb_expr_50.Node #0

dump(n1, name: nil, indent: 0, maxDepth: 1, maxItems: 5)
/*
▿ __lldb_expr_52.Node #0
  - key: 2
  ▹ prev: Optional(__lldb_expr_52.Node)
  ▹ next: Optional(__lldb_expr_52.Node)
*/

dump(n1, name: nil, indent: 0, maxDepth: 2, maxItems: 5)
/*
▿ __lldb_expr_54.Node #0
  - key: 2
  ▿ prev: Optional(__lldb_expr_54.Node)
    ▹ some: __lldb_expr_54.Node #1
  ▿ next: Optional(__lldb_expr_54.Node)
      (1 child)
*/

maxItems: Int = default

出力する行数を指定できます。
maxItems+1の行数が最大で出力されます。
maxItemsに出力が収まらない場合は(2 more children)のようにあと何件あるかが出力されます。

dump(n1, name: nil, indent: 0, maxDepth: 5, maxItems: 2)
/*
▿ __lldb_expr_68.Node #0
  - key: 2
    (2 more children)
*/

どこまでもループするのかと思ったら、一度表示された要素はそれ以上深く追わないようです。
各要素には#0のように番号が振られているので、これを見るとわかりやすそうです。

dump(n1, name: nil, indent: 0, maxDepth: 5, maxItems: 100)
/*
▿ __lldb_expr_70.Node #0
  - key: 2
  ▿ prev: Optional(__lldb_expr_70.Node)
    ▿ some: __lldb_expr_70.Node #1
      - key: 1
      ▿ prev: Optional(__lldb_expr_70.Node)
        ▿ some: __lldb_expr_70.Node #2
          - key: 3
          ▹ prev: Optional(__lldb_expr_70.Node)
          ▹ next: Optional(__lldb_expr_70.Node)
      ▿ next: Optional(__lldb_expr_70.Node)
        ▿ some: __lldb_expr_70.Node #0
  ▿ next: Optional(__lldb_expr_70.Node)
    ▿ some: __lldb_expr_70.Node #2
*/

明日は @Tsuyoposon です!
よろしくお願いします〜〜!

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3