Kotlin中Lambda表达式中的默认参数 [英] Default parameters in lambda expression in Kotlin

查看:358
本文介绍了Kotlin中Lambda表达式中的默认参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个lambda并将其分配给一个变量,并且可以按预期进行以下工作:

I want to create a lambda and assign it to a variable and the following works as expected:

val rollDice = { min: Int, max: Int -> (min..max).random() }

但是,当我尝试为参数分配默认值时,出现错误:

However, when I tried to assign default values to the parameters I got an error:

val rollDice = { min: Int = 1, max: Int = 12 -> (min..max).random() }
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Unexpected tokens (use ';' to separate expressions on the same line)

是否无法在Kotlin中为lambda表达式中的参数分配默认值?

Is it not possible to assign default values to parameters in lambda expressions in Kotlin?

推荐答案

TLDR: Lambda表达式不能具有默认参数.如果需要它们,则应声明一个函数(可以在另一个函数内部).

TLDR: Lambda expressions cannot have default parameters. If you need them, you should declare a function (can be locally inside another function).

详细说明一下,让我们看看如何在Kotlin中定义类似函数的类型.凭直觉,人们希望它们能够相同地工作,但是它们的功能之间存在细微的差异.

To elaborate, let's look at different ways how function-like types can be defined in Kotlin. Intuitively, one would expect them to work the same, but there are subtle discrepancies in their functionality.

1.重载功能

在手动定义函数重载时(以Java方式),不仅可以调用具有任何允许的参数编号的函数,还可以存储在函数引用中使用任何参数数字键入.

When defining function overloads manually (the Java way), it's possible to not just call the function with any allowed argument number, but also store the function reference in a type using any argument number.

fun overload(min: Int, max: Int) = (min..max).random()
fun overload(min: Int) = overload(min, 12)
fun overload() = overload(1, 12)

// Calling is possible with all numbers of arguments, and naming ones at the end
overload()
overload(3)
overload(min=3)
overload(3, 4)
overload(3, max=4)
overload(min=3, max=4)

// Intuitively, all 3 ways of storing work:
val f: (Int, Int) -> Int = ::overload
val g: (Int) -> Int = ::overload
val h: () -> Int = ::overload

// On the other hand, this does NOT compile because of ambiguity:
val i = ::overload

2.具有默认参数的功能

在Kotlin中,更惯用的是使用默认参数.尽管这似乎主要等同于重载函数,但事实并非如此.显着的区别是:仅声明了一个函数,并且类型推断仅在调用时才考虑不同的参数计数,而在通过函数引用进行 storing 时则不考虑. /p>

More idiomatic in Kotlin is the use of default parameters. While this seems to be mostly equivalent to overloaded functions, it's not. The notable difference is: only a single function is declared, and type inference will consider different argument counts only when calling the function, but not when storing it via function reference.

fun default(min: Int = 1, max: Int = 12) = (min..max).random()

// Calling is possible exactly like overloaded functions
default()
default(3)
default(min=3)
default(3, 4)
default(3, max=4)
default(min=3, max=4)

// No ambiguity, f and g have the same type (all parameters)
val f = ::default
val g: (Int, Int) -> Int = ::default

// However, storing in a function type taking fewer arguments is NOT possible
val h: (Int) -> Int = ::default
val i: () -> Int = ::default

3.匿名函数

即使在声明中,匿名函数也不允许默认参数,因此只有一种方法可以调用它们.此外,存储它们的变量属于函数类型,它将丢失有关参数名称的信息,从而阻止使用命名参数进行调用.

Anonymous functions allow no default parameters even in the declaration, so there's only one way of calling them. Furthermore, the variable storing them is of function type, which loses information about the parameter names and thus prevents a call with named arguments.

val anonymous = fun(min: Int, max: Int) = (min..max).random()
val anonymous: (Int, Int) -> Int = fun(min: Int, max: Int) = (min..max).random()

// Only one way to call
anonymous(3, 4)

// No ambiguity, f and g have the same (full type)
val f = anonymous
val g: (Int, Int) -> Int = anonymous

// Mistake, which compiles: this declares h as a *property*,
// with type KProperty<(Int, Int) -> Int>
val h = ::anonymous

// Calling with named arguments is NOT possible
anonymous(3, 4)         // OK
anonymous(min=3, max=4) // error

4. Lambda表达式

与匿名函数一样,lambda表达式不允许使用默认参数,也不能使用命名参数进行调用.由于它们会像(Int, Int) -> Int这样的函数类型立即存储,因此它们受到与引用实际函数的函数类型相同的限制.

Like anonymous functions, lambda expressions allow no default parameters and cannot be called with named arguments. Since they are stored immediately as a function type like (Int, Int) -> Int, they undergo the same restrictions as function types referring to actual functions.

类型推断仅在参数类型在lambda表达式中或在要分配给的函数类型中指定的情况下有效:

Type inference only works if the parameter types are specified either in the lambda expression, or in the function type to assign to:

// OK:
val lambda = { min: Int, max: Int -> (min..max).random() }
val lambda2: (Int, Int) -> Int = { min, max -> (min..max).random() }

// Type inference fails:
val lambda3 = { min, max -> (min..max).random() }


这里的主要要点是,这4个可调用对象在支持相同的基本功能的同时,在以下几点上有所不同:


The main takeaway here is that these 4 callables, while supporting the same basic functionality, differ in the following points:

  • 允许声明和调用默认参数
  • 允许通过考虑默认参数的函数引用进行存储
  • 允许使用命名参数进行调用
  • Allows declaration and calling of default parameters
  • Allows storing via function reference that considers default parameters
  • Allows calling with named arguments

通过将可调用对象称为函数类型(这是匿名函数和lambda的唯一选项),您将丢失原始声明中存在的信息.

By referring to the callables as function types (which is the only option for anonymous functions and lambdas), you lose information that's present in the original declaration.

这篇关于Kotlin中Lambda表达式中的默认参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆