String.format работает странно в Kotlin и Java - PullRequest
1 голос
/ 11 апреля 2019

Я пытался переместить кодовую базу в Kotlin с Java. Но я обнаружил странное поведение в String.format.

У меня есть оба одинаковых кода (и функции, также) в Kotlin и Java.

fun callScriptMethod(methodName: String, vararg args: Any): String {
        var format = methodName
        if (!format.contains("javascript:")) {
            format = String.format("javascript:%s", format)
        }

        val objects = mutableListOf<Any>()
        for (arg in args) objects.add(arg)

        if (!objects.isEmpty()) {
            format += "("
            var i = 0
            val icnt = objects.size
            while (i < icnt) {
                format += "\'%s\'"
                if (i != icnt - 1) {
                    format += ", "
                }
                i++
            }

            format += ")"
        } else {
            format += "()"
        }

        val message = String.format(Locale.getDefault(), format, args)
        return message
    }
public static String callScriptMethod(String methodName, Object... args) {
        String format = methodName;
        if (!format.contains("javascript:")) {
            format = String.format("javascript:%s", format);
        }

        List<Object> objects = Arrays.asList(args);
        if (!objects.isEmpty()) {
            format += "(";
            for (int i = 0, icnt = objects.size(); i < icnt; i++) {
                format += "\'%s\'";
                if (i != icnt - 1) {
                    format += ", ";
                }
            }

            format += ")";
        } else {
            format += "()";
        }

        String message = String.format(format, args);
        return message;
    }

и некоторый тестовый код.

fun main() {
    val result = Java.callScriptMethod("nativeCallback", "1", "d8d8441n24n134n",
        "dasqhjidhkdhaskjdfhawoiudnqwaidnqwioldjnqawskld:djoashdojashdlkjasdjhas", "0")
    println(result)

    val result2 = Kotlin.callScriptMethod("nativeCallback", "1", "d8d8441n24n134n",
        "dasqhjidhkdhaskjdfhawoiudnqwaidnqwioldjnqawskld:djoashdojashdlkjasdjhas", "0")
    println(result2)
}

Я могу ожидать, что результат будет javascript:nativeCallback('1', 'd8d8441n24n134n', 'dasqhjidhkdhaskjdfhawoiudnqwaidnqwioldjnqawskld:djoashdojashdlkjasdjhas', '0').

Но в версии Kotlin есть исключение MissingFormatArgumentException.

Итак, я попытался отладить эти коды, чтобы убедиться, что формат успешно сгенерирован.

Java: javascript:nativeCallback('%s', '%s', '%s', '%s')

Котлин: javascript:nativeCallback('%s', '%s', '%s', '%s')

Оба имеют одинаковый результат и имеют одинаковые args, но имеют разные результаты.

javascript:nativeCallback('1', 'd8d8441n24n134n', 'dasqhjidhkdhaskjdfhawoiudnqwaidnqwioldjnqawskld:djoashdojashdlkjasdjhas', '0')
Exception in thread "main" java.util.MissingFormatArgumentException: Format specifier '%s'
    at java.util.Formatter.format(Formatter.java:2519)
    at java.util.Formatter.format(Formatter.java:2455)
    at java.lang.String.format(String.java:2981)
    at Kotlin.callScriptMethod(Kotlin.kt:31)
    at TestKt.main(test.kt:11)
    at TestKt.main(test.kt)

Итак, я хочу знать, в чем проблема. Как я могу это сделать?

1 Ответ

4 голосов
/ 11 апреля 2019

Поскольку vararg становится массивом после входа в тело функции, вы должны использовать оператор spread , чтобы передать его как vararg.https://kotlinlang.org/docs/reference/functions.html#variable-number-of-arguments-varargs

Когда мы вызываем функцию vararg, мы можем передавать аргументы один за другим, например, asList (1, 2, 3) или, если у нас уже есть массив ичтобы передать его содержимое в функцию, мы используем оператор распространения (префикс массива *):

val message = String.format( format, *args)

Разница с Java состоит в том, что Java фактически позволяет передавать массив как vararg напрямую, см.этот пост SO: Могу ли я передать массив в качестве аргументов методу с переменными аргументами в Java?

т.е. Object... в Java технически идентичен Object[], нет "настоящие "разные вещи" в Java, в то время как vararg - это совсем другое в Котлине.

...