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

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

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

```swift:
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 には中身を確かめたい変数を入れます。
今回はできるだけ多くネストした変数として、重連結リストを利用します。

```swift
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で試しに出力してみると、中身が全然わかりませんね。

```swift
print(n0) //__lldb_expr_69.Node
```

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

```swift
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

``` swift
 where TargetStream : TextOutputStream 
```
とあるように、TargetStreamはTextOutputStream を継承したものである必要がありそうです。
TextOutputStream がわからなかったので調べてみました。[公式リファレンス](https://developer.apple.com/documentation/swift/textoutputstream)
リファレンスによるとTextOutputStreamはprotocolとして宣言されており、
String型, Substring型はこのprotocolに準拠しているそうです。

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

```swift
var stream: String = ""
dump(n0, to: &stream, name: "", indent: 5, maxDepth: 5, maxItems: 5)
dump(stream)
```
String型として宣言されたstreamに文字列が追加されていますね。

```swift
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でも同様にやってみましたが、改行は無視されるようです。

```swift
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
行頭のクラス名の前にラベルを付けることができます。
ログが増えまくってきたときに使うと便利かも。

```swift
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のようですね

```swift
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は０です。

```swift
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
どこまで追うかを決められます。

```swift
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)**のようにあと何件あるかが出力されます。

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

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

```swift
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 です！
よろしくお願いします〜〜！