LoginSignup
11
12

More than 5 years have passed since last update.

for文内で宣言するクロージャにインクリメントする引数を渡してはいけない

Last updated at Posted at 2015-05-24

別に言語は関係なさそうだけど、よくわかっていなかったのでメモ。
ページングの実装でリスナーを生成するときにハマった。初心者は気をつけよう。

Swift

func getF(num:Int) -> Void -> Void {
  return {
    println(num)
  }
}

var list1: [(Void -> Void)] = Array()
var list2: [(Void -> Void)] = Array()
var list3: [(Void -> Void)] = Array()
for (var i = 0; i < 3; i++) {
  let n = i
  list1.append({println(n)})
  list2.append({println(i)})
  list3.append(getF(i))
}
for f in list1 { f() } // 0 1 2
for f in list2 { f() } // 3 3 3
for f in list3 { f() } // 0 1 2

Javaについてコメントいただいたので、Javascriptも試してみた。

Javascript

var list1 = []
var list2 = []
var list3 = []
function getF(num) {
  return function() {
    console.log(num)
  }
}
for (var i = 0; i < 3; i++) {
  var n = i
  list1.push(function(){console.log(n)})
  list2.push(function(){console.log(i)})
  list3.push(getF(i))
}
list1.forEach(function(f){f()}) // 2 2 2
list2.forEach(function(f){f()}) // 3 3 3
list3.forEach(function(f){f()}) // 0 1 2

こちらは一旦別の変数に入れる対応でもだめみたい。

ES6ならletでイケる!とのコメントをいただいたのでこちらも試してみた。
こんなサービスがあるあたり流石js界隈。

ES6

var list1 = []
var list2 = []
var list3 = []
function getF(num) {
  return function() {
    console.log(num)
  }
}
for (let i = 0; i < 3; i++) {
  let n = i // var だとダメだった( 2 2 2 )
  list1.push(function(){console.log(n)})
  list2.push(function(){console.log(i)})
  list3.push(getF(i))
}
list1.forEach(function(f){f()}) // 0 1 2
list2.forEach(function(f){f()}) // 0 1 2
list3.forEach(function(f){f()}) // 0 1 2

let n = i のところを var n = iと書いたらダメだった。
まあletがあるということは、ES6は基本var は使わない方がいいということなのかな。

11
12
6

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
11
12