代码之家  ›  专栏  ›  技术社区  ›  Pierre Henry

为什么kotlin中的chaining.map()和.filter()不能按预期工作?

  •  3
  • Pierre Henry  · 技术社区  · 8 年前

    我正试图将一个对象列表映射到另一个类型的对象列表,然后筛选该列表,然后映射到第三个类型的列表,就像我在Java8+中通过链接流所做的那样(我更改了类和变量名以使其更有意义,但结构与代码中的相同):

    val results: List<AccountDto> = listOfPersons
                    .map { person -> getPersonAccount(person) }
                    .filter { account ->
                        if(validateAccount(account)){ // validateAccount is a function with boolean return type
                            // do something here like logging
                            return true
                        }
                        // do something else...
                        return false
                    }
                    .map { account ->
                         toDto(account) // returns an AccountDto
                    }
    

    我在 return true return false 筛选器lambda中的语句:

    Error:(217, 32) Kotlin: The boolean literal does not conform to the expected type List<AccountDto>
    

    如果我对筛选器谓词使用匿名函数,则可以编译:

    .filter (fun(account):Boolean{
                    if(validateAccount(account)){ 
                            // do something here like logging
                            return true
                        }
                        // do something else...
                        return false
                })
    

    为什么在这种情况下类型推断会失败?

    有没有可能我用一个兰姆达就可以了?

    2 回复  |  直到 8 年前
        1
  •  10
  •   HTNW    8 年前

    return 从最近的封闭函数或匿名函数(即 fun(a1: T1, ..., an: TN): TR = ... )中。记忆法是不合格的 返回 去最近的地方 fun 是的。lambda不是匿名函数,因此 返回 实际上是从包含整个 map / filter 表达。您可以使用带标签的退货:

    val results: List<AccountDto> = listOfPersons
                    .map(::getPersonAccount)
                    .filter { account ->
                        if(validateAccount(account)){
                            // etc.
                            return@filter true
                        }
                        // etc.
                        return@filter false
                    }
                    .map(::toDto)
    

    lambda表达式使用传递给它的函数隐式标记,因此不需要显式添加标签。如果您愿意,您可以:

    val results: List<AccountDto> = listOfPersons
                    .map(::getPersonAccount)
                    .filter lam@{ account ->
                        if(validateAccount(account)){
                            // etc.
                            return@lam true
                        }
                        // etc.
                        return@lam false
                    }
                    .map(::toDto)
    

    但是 if / else 它本身就是一个表达式,所以只要没有 返回 S.

    val results: List<AccountDto> = listOfPersons
                    .map(::getPersonAccount)
                    .filter { account ->
                        if(validateAccount(account)) {
                            // etc.
                            true
                        } else {
                            // etc.
                            false
                        }
                    }
                    .map(::toDto)
    
        2
  •  4
  •   Kiskae    8 年前

    你之所以会犯这个错误是因为 return 在lambda中,函数本身往往从最外层的作用域返回。

    lambdas期望隐式返回(每个执行路径上的最后一个表达式)或显式标记的返回 return@filter 是的。

    移除 返回 或者用 返回@过滤器 将修复错误。