Как я могу динамически привести массив, чтобы соответствовать аргументам функции, используя отражение? - PullRequest
0 голосов
/ 31 декабря 2018

Я работаю над проектом, в котором я хочу проанализировать некоторые входные данные и использовать их для вызова функции.Входные данные - это строка, которая обрабатывается во время выполнения, а вызываемая функция определяется разработчиком.Токенизированный ввод будет передан указанной функции.

Это демонстрирует, как можно использовать код.Вы передаете функцию, что-то для анализа и набор tokenPatterns, с которыми можно сопоставить генерируемые токены.

fun main(args : Array<String>) {

    val f = Funcs()

    val myColor: String = f.whatColor(Color.GREEN) // Expected
    val theirColor: String = Processor.process(f::whatColor, "green", Color.values().toSet())

    println(myColor == theirColor) // Should be true
}

class Funcs {
    fun whatColor(color: Color): String {
        return when (color) {
            Color.RED -> "nice red"
            Color.GREEN -> "cool green"
        }
    }
}

enum class Color(override val pattern: Regex) : TokenPattern {
    RED(Regex("red")),
    GREEN(Regex("green"))
}

Код ниже показывает базовую версию того, как она работает в настоящее время (или, скорее, нет).По сути, я токенизирую входные данные на основе набора tokenPatterns, а затем вызываю указанную функцию, используя эти токены.Проблема в том, что мне нужно привести их обратно к исходной реализации шаблона (в данном случае перечислению Color), чтобы я мог вызвать исходную функцию с ними.

/**
 * Extend to define custom tokens.
 */
interface TokenPattern {
    val pattern: Regex
}

class Token<T: Any>(val type: KClass<out T>)

/**
 * Tokenizes and runs functions
 */
object Processor {

fun process(func: KFunction<String>, input: String, tokenPatterns: Set<TokenPattern>): String {
    val tokens = tokenize(input, tokenPatterns)
    return runIt(func, tokens)
}

private fun tokenize(input: String, tokenPatterns: Set<TokenPattern>): List<Token<*>> {
    return tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }
}

private fun runIt(func: KFunction<String>, tokens: List<Token<*>>): String {
    val args: Array<Any> = tokens.toTypedArray()
    // Some casting needs to be done
    return func.call(*args)
}

Фактический код сложнее, чемэто, но это более или менее иллюстрирует, как это работает вместе.Основная проблема, с которой я столкнулся, заключается в том, что я не уверен, как я могу динамически привести к реализации Color, чтобы передать ее функции с помощью отражения.Я также открыт для других способов решения этой задачи, и любая помощь будет принята с благодарностью!Спасибо!

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Просто сохраните tokenPattern в токене, передайте эти tokenPatterns в качестве аргументов, и отражение сможет разыграть его соответствующим образом.

Вы можете сделать токен следующим образом:

class Token(val original: TokenPattern)

Затем вызовите функцию следующим образом:

private fun runIt(func: KFunction<String>, tokens: List<Token>): String {
    val args: Array<Any> = tokens.map { it.original }.toTypedArray()
    return func.call(*args)
}
0 голосов
/ 31 декабря 2018

Я полагаю, что это может быть достигнуто либо сохранением, либо извлечением базового перечисления реализации в сам токен.В этой строке класс хранится, но я не уверен, относится ли он к какому-либо Color или к определенному Color.Red или Color.Green.

tokenPatterns.filter { it.pattern.matches(input) }.map { Token(it::class) }

Возможно, это можно восстановить примерно так, но я не уверен, как именно это написать.

val castedArgs: Array<Any> = tokens.map { it.type.cast(it) }.toTypedArray()

Возможно, вместо приведения я мог бы как-то воссоздать enum?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...