mike-neckのブログ

Java or Groovy or Swift or Golang

try-with-resources に複数のリソースを指定した場合の close の実行順

年末年始に書いていたコードで気になったことがあったので調べた。

f:id:mike_neck:20181019112748p:plain

結論だけ先に書くと、 try-with-resources に選択したリソースの順番の逆順になる。


Java9 以降で使えるようになった effevtively-final variables in try-with-resources の実行順がどうなるのかちゃんと理解していなかったが、 Java 言語仕様には書かれていた。

引用すると次の箇所

Resources are initialized in left-to-right order. ...

リソースは左から右の順番に初期化される

Resources are closed in the reverse order from that in which they were initialized. ... An exception from the closing of one resource does not prevent the closing of other resources.

リソースは初期化とは逆順にクローズされる。クローズ時に例外が発生した場合でも他のリソースのクローズに支障をきたさない

ここで、初期化すでにしているのではないかと思うのだが、続く 14.20.3.1 を読んで try-with-resources スコープの中での初期化のことなのかと思ったのだが誤解しているかもしれない。

14.20.3.1 の内容を一部だけ書くと、

try (autoCloseable) {

}

となっていたものは、一度次のような形に変換されるらしい。

try (final T resource = autoCloseable) {

}

というわけで、次のコードを jshell で動かして実験する。

try にて指定するリソースに 0 からの順番に名前をつける。一方、クローズする順番を 0 から数えていく。また、 4 番目(名前は 3)のリソースのクローズ時に例外を発生させる

この時に、仕様通りであれば、

int[] count = new int[] { 0 };

AutoCloseable autoCloseable(int num) {
  return () -> {
    System.out.println("num: " + num + " -> " + count[0]++);
    if (num % 4 == 3) {
      throw new Exception("num: " + num);
    }
  };
}

try {
  final AutoCloseable a0 = autoCloseable(0);
  final AutoCloseable a1 = autoCloseable(1);
  final AutoCloseable a2 = autoCloseable(2);
  final AutoCloseable a3 = autoCloseable(3);
  final AutoCloseable a4 = autoCloseable(4);
  try (a0; a1; a2; a3; a4) {
    System.out.println("action in try");
  } catch (final Exception e) {
    System.out.println(e.getMessage());
    throw e;
  }
} catch (final Exception e) {
  System.out.println("outer: " + e.getMessage());
} finally {
  System.out.println("finish");
}

これの出力結果は次のとおりとなった。

action in try
num: 4 -> 0
num: 3 -> 1
num: 2 -> 2
num: 1 -> 3
num: 0 -> 4
num: 3
outer: num: 3
finish

結論

try(r0;r1;r2 ...) と複数のリソースを指定した場合のクローズ実行順は逆順、つまり r2, r1, r0 の順番になる

合同勉強会 in 大都会岡山 にて 『Vim 入門』というタイトルで LT してきました #gbdaitokai

f:id:mike_neck:20181208195209p:plain
Vim 入門

2018/12/22 開催された 合同勉強会 in 大都会岡山 にて『Vim 入門』というタイトルで LT をしてきました。

gbdaitokai.connpass.com

どうやら評判がよかったのか、 LT 枠での表彰は当初予定になかったようでしたが、審査員特別賞なるものをいただきました。


特別賞を頂いた LT の資料はこちらです。

www.slideshare.net

なお、詳細な内容は以前の記事に書いたとおりです。

mike-neck.hatenadiary.com

また、デモで使ったスクリプト等はこちらより入手可能です(ただし、 デモ中にちゃんとあげたやつですよという証跡が欲しかったので、 CodePipeline / CloudFormation でデプロイするようにしてあります。あと、 readme をメンテし忘れています)

github.com

また、僕の LT に対する反応は以下のまとめの 16 〜 17 ページあたりにまとめられています。

togetter.com


今回の LT は非常に良い反応を得られるできの良さでしたが、多分まぐれなので何が良かったのか反省しておきたいと思います。

Swift 用の正規表現ライブラリー

これは Qiita のアドベントカレンダー2018 の19日目のエントリーです。

qiita.com

Swift の勉強を始めたのが今年の5月末からで、約半年程度 Swift をやってきました。ただ、僕は仕事では一切 Swift を書いていないので、知見に溢れた他の方のエントリーを楽しみにしています(突然の煽り)。

f:id:mike_neck:20180609045321p:plain


Swift を勉強し始めて3ヶ月くらいの頃に、ふとしたきっかけで正規表現が欲しくなりました。調べてみたところどうやら Swift 単体で使える正規表現がなく、 NSRegularExpression を使って、結構面倒そうなコードを書くらしいということがわかりました。しかし、これが Linux で使えるのかわからない(実際には使える)ので、その時は正規表現を使わない方法でとりあえず回避しました。

また、後日、詳しそうな人に尋ねたところ、 NSRegularExpression をラップして String などの extension とするライブラリーを自作しているとのことでした。 実際、 GitHub で 「 Swift regex 」 で調べてみると、そのようなライブラリーがたくさんあるようです。


というわけで、そのようなライブラリーを使えばよいのですが、 Swift の勉強がてら正規表現ライブラリーを作ってみるのも面白そうだと思い、作ってみることにしました。レポジトリーはこちらです。

github.com


仕組み

仕組みはいたって簡単で、 C 言語の正規表現ライブラリーをラップしているだけです。今のところ POSIX正規表現(regex.h)をラップしたもののみを提供しています。Swift から C 言語を呼び出す方法等は過去にエントリーを書いているので、そちらを見ると良いと思います。

mike-neck.hatenadiary.com

mike-neck.hatenadiary.com


導入方法

Swift Package Manager を使います。残念ながらその他のビルドシステムの方法は知らないので、PRくれるとノールックでマージすると思います。

次の依存ライブラリーを追加します。

  dependencies [
    .package(url: "https://github.com/mike-neck/swift-regex.git", from: "0.1"),
  ]

ターゲットに加えます。

targets [
    .target(name: "YourAwesomeApp", dependencies: [
        "SwiftRegex",
        "POSIXRegex",
    ]),
]

このライブラリーには今のところ3つモジュールがあります。

  • SwiftRegex - API を定めているモジュール
  • POSIXRegex - APIPOSIX 実装モジュールで、次の CPOSIXRegex モジュールをラップしています
  • CPOSIXRegex - POSIX正規表現を呼び出す C で書かれたモジュール

これらのうち、 API と 実装モジュールをターゲットに加えれば、このライブラリーを利用できます。


コード例

import POSIXRegex
import SwiftRegex

SwiftRegexImplementation.by.usePosix() // 1

guard let regex = pattern(of: "ba").compile() else { // 2
    fatalError { "cannot compile pattern \"ba\"" }
} 

let matcher = regex.matcher(for: "foo-bar-baz") //3
matcher.matches // -> true //4
  1. SwiftRegexSwiftRegexImplementation という長ったらしい名前の構造体があり、それの static プロパティ byusePosix() という関数が生えているので、これを呼び出すと、 POSIX 実装の正規表現が使えます。
  2. pattern(of:) という関数があるので、それを呼び出してからコンパイルします。コンパイルの結果は SwiftRegex? となっており、正規表現が間違えているなどコンパイルできない場合は nil が返ってきます。
  3. 検索ソースの文字列を matcher(for:) 関数にわたすと検索結果が返ってきます
  4. 今のところ matches プロパティで検索結果だけが取り出せるようになっています。(今後、置換を実装していこうと思っています)

という感じのライブラリーですが、どうやら Swift5 以降に正規表現が加わるかもしれないそうなので短命に終わるかもしれないです。「へぇ〜」と思ったそこのアナタ!、ぜひGitHubでスターを付けてってください!【2018/12/19 15:45 間違えているので修正しました】