2015-03-06 13 views
8

Ho pensato che QML supportasse le funzioni lambda a causa del supporto JavaScript delle funzioni anonime e del fatto che le funzioni sono oggetti di prima classe, ma non funzionano come mi aspettavo. Prendete questo codice:QML: la funzione Lambda funziona in modo imprevisto

Item { 
    property var items: [] 

    function handler(item) { 
     console.log(item); 
    } 

    Component.onCompleted: { 
     for (var i = 0; i < 3; ++i) { 
      var item = someObj.createObject(); 
      item.someValueChanged.connect(function() { 
       handler(item); }); 

      items.push(item); 
      console.log("Adding:", item); 
     } 
    } 

    Component { 
     id: someObj 

     Item { 
      property bool someValue: false 

      Timer { 
       running: true 
       onTriggered: { 
        parent.someValue = true; 
       } 
      } 
     } 
    } 
} 

Sto cercando di utilizzare il lambda function() { handler(item); } in modo che quando il segnale viene emesso someObj::someValueChanged l'elemento che emette è passato alla funzione handler(item).

I presume che ogni ciclo creerebbe una nuova istanza del lambda e che il riferimento item porterebbe il riferimento del someObj istanza creata in quel ciclo (cioè item sarebbe catturato dal lambda). Ma questo non sembra essere il caso come l'output è:

qml: Adding: QQuickItem_QML_1(0x2442aa0) 
qml: Adding: QQuickItem_QML_1(0x2443c00) 
qml: Adding: QQuickItem_QML_1(0x2445370) 
qml: QQuickItem_QML_1(0x2445370) 
qml: QQuickItem_QML_1(0x2445370) 
qml: QQuickItem_QML_1(0x2445370) 

Come si può vedere, sia l'intera funzione viene sostituito ad ogni ciclo o solo il riferimento item, in modo che alla fine l'ultimo creato solo someObj è riferito a. Qualcuno può spiegarmi perché i lambda (se è persino quello che è) non funzionano come mi aspetto? E questo è un problema di QML o di JavaScript generico?

risposta

11

provare qualcosa di simile:

item.someValueChanged.connect(function(temp) { 
    return function() { 
     handler(temp)} 
}(item)) 

intuitiva, giusto? : D

Se JS utilizzava "scope scope" ci sarebbero 3 diversi item a cui si fa riferimento per ogni iterazione del ciclo e "funzionerebbe come previsto". Ma con "scope della funzione" c'è un solo riferimento a item e fa riferimento al suo valore finale, quindi la necessità di usare quell'hack per "catturare" ogni valore nel tempo.

+0

Ah, questo ha senso (per JS comunque). Grazie! – cmannett85

+0

@ cmannett85 - cosa succederebbe in C++ se si tenta di eseguire un lambda in ritardo, facendo riferimento ai locals di una funzione che è andata oltre lo scopo? Il caso migliore se fosse in pila all'inizio e lo stack non è andato a quella profondità in seguito e quella memoria non viene sovrascritta, potrebbe funzionare, ma molto probabilmente andrà in crash. – dtech

+0

Vero tranne che in C++ è possibile specificare cosa viene catturato _e come_. Qualcosa che JS non supporta (almeno la versione utilizzata da QtQuick). – cmannett85

Problemi correlati