V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
abbenyyy
V2EX  ›  问与答

有懂 kotlin 的么,想请教一个函数为 lambda 表达式的写法的出处。

  •  
  •   abbenyyy · 2018-12-24 13:39:02 +08:00 · 2763 次点击
    这是一个创建于 2196 天前的主题,其中的信息可能已经有所发展或是发生改变。
    viewModel.gardenPlantings.observe(viewLifecycleOwner, Observer { plantings ->
           binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
    })
    

    源码出处

    这个 Observer 是什么写法呢?真搞不懂,kotlin 感觉太天马行空了,来个大神指教一下,谢谢

    20 条回复    2018-12-26 23:12:43 +08:00
    jinksw
        1
    jinksw  
       2018-12-24 13:44:34 +08:00
    只有一个函数声明的接口可以用 Lambda 代替?

    类似 setOnClickListener{
    view->xxx
    }
    abbenyyy
        2
    abbenyyy  
    OP
       2018-12-24 13:45:37 +08:00
    @jinksw 这个我知道,谷歌的这个为何要在前面加上 Observer 呢
    Mystery0
        3
    Mystery0  
       2018-12-24 14:01:54 +08:00 via Android
    Observer 是一个接口,这个接口里面只有一个函数,所以可以简写成这样
    Mystery0
        4
    Mystery0  
       2018-12-24 14:02:24 +08:00 via Android
    其实看一下 Observer 的定义应该就清楚了
    jinksw
        5
    jinksw  
       2018-12-24 14:06:01 +08:00
    @abbenyyy 不加那个 Observer 应该也可以 只是指出类型了
    abbenyyy
        6
    abbenyyy  
    OP
       2018-12-24 14:11:48 +08:00
    @Mystery0 那为何
    ```
    val livePlantList = Transformations.switchMap(growZoneNumber) {
    if (it == NO_GROW_ZONE) {
    plantRepository.getPlants()
    } else {
    plantRepository.getPlantsWithGrowZoneNumber(it)
    }
    }
    ```
    [源码出处]( https://github.com/googlesamples/android-sunflower/blob/a85cd9b49a924ee2ad029685225d6d071de6bd15/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/PlantListViewModel.kt#L41)
    Transformations.switchMap 第二个参数也是接口,Transformations.switchMap 的最后一个 lambda 表达式参数移出括号外的方式,并不能套用在 Observer 上面,也就是
    ```
    viewModel.gardenPlantings.observe(viewLifecycleOwner) { plantings ->
    binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
    }
    ```
    这个写法并不能编译通过
    abbenyyy
        7
    abbenyyy  
    OP
       2018-12-24 14:14:14 +08:00
    @jinksw 如同我上面说的,如果函数最后一个参数是 lambda 表达式可移出括号外,但是 Observer 如果这样写,编译并不能通过。所以我搞不懂为何有这两种方式
    loshine1992
        8
    loshine1992  
       2018-12-24 14:17:33 +08:00
    从这个简化的

    ```kotlin
    viewModel.gardenPlantings.observe(viewLifecycleOwner, object : Observer {

    override fun 方法名(plantings: 参数类型) {
    binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
    }

    })
    ```

    最简化的写法是这样

    ```kotlin
    viewModel.gardenPlantings.observe(viewLifecycleOwner) {
    binding.hasPlantings = (it!= null && it.isNotEmpty())
    }
    ```
    jinksw
        9
    jinksw  
       2018-12-24 14:22:33 +08:00
    @loshine1992 然而楼主说这样不行
    🤔 到底是为啥呢 是不是最后一个参数 是泛型类 的缘故
    holmesabc
        10
    holmesabc  
       2018-12-24 14:23:04 +08:00
    Observer 是个 java 里面的单方法 接口。就能简写
    abbenyyy
        11
    abbenyyy  
    OP
       2018-12-24 14:27:47 +08:00
    @loshine1992 你可以 clone 下来谷歌的 android-sunflower 项目,按照你的方式改写一下,并不能编译通过,我已经试过了
    jinksw
        12
    jinksw  
       2018-12-24 14:32:23 +08:00
    loshine1992
        13
    loshine1992  
       2018-12-24 14:36:32 +08:00
    @abbenyyy #2 这个情况下大概率有另外一个方法也接受一个接口的参数,

    observe(viewLifecycleOwner: A 参数, observer: Observer)
    observe(viewLifecycleOwner: A 参数, subscriber: Subscriber)

    此时需要区分,不能直接用 lambda
    jinksw
        14
    jinksw  
       2018-12-24 14:42:20 +08:00
    感觉应该是编译器的锅 我看那个 observer 方法也没有重载
    abbenyyy
        15
    abbenyyy  
    OP
       2018-12-24 14:54:39 +08:00
    @jinksw 好像是因为 observer 方法有一个通配符泛型<? super T>,所以才需要明确泛型吧
    dagger2
        16
    dagger2  
       2018-12-24 16:56:50 +08:00
    viewModel.gardenPlantings.observe 是个 java 方法,接收的参数是一个 Observer 的实现,而不是() -> Unit
    pipicat
        17
    pipicat  
       2018-12-24 17:26:10 +08:00
    应该跟泛型有关系。
    pipicat
        18
    pipicat  
       2018-12-24 17:33:28 +08:00
    val a = object : View.OnClickListener {
    override fun onClick(v: View?) {
    }
    }

    val b = object : Observer<Any>{
    override fun onChanged(t: Any?) {
    }
    }

    idea 提示后简化成
    val a = View.OnClickListener { }

    val b = Observer<Any> { }

    这里 observer 不加泛型是无法单独声明的。
    而 livedata 的这个方法泛型已经确定了,所以
    viewModel.gardenPlantings.observe(viewLifecycleOwner, Observer { plantings ->
    binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
    })
    上的泛型没有显式的写出来。
    pipicat
        19
    pipicat  
       2018-12-24 17:45:33 +08:00
    测试了一下 java8 的代码。同样的代码,java8 不用显式写 Observer,但是参数要写出来。
    SoloCompany
        20
    SoloCompany  
       2018-12-26 23:12:43 +08:00 via iPad
    java8 的 function interface 和一 kotlin,的 KFunction 并不是同一种类型,需要显式转换,所以需要显式构造 Observer 接口
    java8 code 则是类型推断系统自动把 lambda 转换为推断出来的 function interface 也就是说 observer,不需要通过显式的类型转换
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1027 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:34 · PVG 03:34 · LAX 11:34 · JFK 14:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.