2017-05-27 1 views
0

Quelle serait une Kotlin autre idiomatiques à l'extrait de coroutine python suivant:Kotlin alternative au rendement coroutine Python et envoyer

def generator(): 
    c = 1 
    while True: 
    op = yield c 
    if op == 'inc': 
     c += 1 
    elif op == 'mult': 
     c *= 2 

# main 
g = generator() 
a = g.send(None) # start 
b = g.send('inc') 
c = g.send('mult') 
d = g.send('inc') 

print([a, b, c, d]) # 1, 2, 4, 5 

donc j'ai besoin obtenir des valeurs de la coroutine (? Via un canal), mais aussi envoyer les valeurs de retour dans la coroutine. Ai-je besoin de deux canaux pour ça?

+1

Quelles solutions avez-vous essayé? Vous devriez le signaler comme une tentative de solution qui fonctionne ou ne fonctionne pas. Sinon vous dites "écrivez mon code s'il vous plaît" au lieu de "ce code qui DEVRAIT ne pas fonctionner" –

+0

Vous définissez op sur c qui est 1, donc il ne répondra jamais à vos conditions d'incrémentation ou de multiplication. – alex

Répondre

2

Les générateurs bidirectionnels présents en Python et en ES6 ne sont pas vraiment idiomatiques dans Kotlin, car Kotlin est un langage typé statiquement et donc les générateurs bidirectionnels sont assez maladroits à utiliser. Il suffit de jeter un oeil à la g.send(None) dans le code ci-dessus pour comprendre pourquoi il en est ainsi. Ainsi, l'implémentation de générateurs bidirectionnels n'est pas fournie dans la bibliothèque standard de Kotlin ni dans les bibliothèques de support. Cependant, le support des coroutines en langage Kotlin est assez générique et des générateurs bidirectionnels peuvent être implémentés, si besoin est, pour se comporter exactement comme en Python et ES6. L'implémentation correspondante est disponible here et ne prend que quelques douzaines de lignes de code.

Avec la mise en œuvre au-dessus du générateur à deux voies, votre code Python peut être traduit directement en ligne par ligne Kotlin:

fun generator() = generate<Int, String> { 
    var c = 1 
    while (true) { 
     val op = yield(c) 
     when (op) { 
      "inc" -> c += 1 
      "mult" -> c *= 2 
     } 
    } 
} 

fun main(args: Array<String>) { 
    val g = generator() 
    val a = g.next("") // start 
    val b = g.next("inc") 
    val c = g.next("mult") 
    val d = g.next("inc") 
    println("$a $b $c $d") // 1, 2, 4, 5 
} 

Ce code fonctionne aussi bien que sa version Python, il est cependant pas idiomatique pour une multitude de raisons. D'une part, le support de corotines dans Kotlin permet de définir des fonctions de suspension arbitraires et permet ainsi d'exprimer un comportement similaire sans utiliser de marqueur de départ arbitraire ni d'utiliser des chaînes pour désigner les opérations. Vous pouvez directement définir un objet ayant inc et mult comme opérations de suspension de première classe ou, au moins, modifier l'implémentation de sorte qu'un appel de démarrage fictif ne soit pas nécessaire. Vous êtes invités à étudier coroutines design document qui explique toutes les primitives de bas niveau que Kotlin fournit et a un certain nombre d'exemples pour vous aider à démarrer.