解析Kotlin中的Unit【笔记摘要】

1. Kotlin的Unit 和 Java的void 的区别

// Java
public void sayHello() {
  System.out.println("Hello!")
}

// Kotlin
fun sayHello(): Unit {
  println("Hello!")
}

Unit 和 Java 的 void 真正的区别在于,void 是真的表示什么都不返回,而 Kotlin 的 Unit 却是一个真实存在的类型:

//Unit的源码,这表明它是一个object单例类
public object Unit {
    override fun toString() = "kotlin.Unit"
}

2. 省略Unit,Kotlin会自动补上

一个完整的”无返回值“的函数写法如下,即返回类型为Unit,函数最后return Unit

fun sayHello() : Unit {
  println("Hello!")
  return Unit
}

当函数返回类型是Unit时,我们是可以省略掉函数的返回类型的,因为 Kotlin 也会帮我们自动加上

fun sayHello() {
  println("Hello!")
  return Unit
}

return 我们一样可以省略不写,Kotlin 也会帮我们自动加上

fun sayHello() : Unit {
    println("Hello!")
}

这两个 Unit 是不一样的,上面的是 Unit 这个类型,下面的是 Unit 这个单例对象。这个并不是 Kotlin 给 Unit 的特权,而是 object 本来就有的语法特性
包括你也可以这样写:

val unit: Unit = Unit

因此全都省略的情况,实际上就是返回类型为Unit,并且最后一行返回了Unit这个单例对象

fun sayHello() {
  println("Hello!")
}

3. Unit总结

所以在结构上,Unit 并没有任何的特别之处,它就只是一个 Kotlin 的 object 而已。
它的特殊之处,更多的是在于语义和用途的角度:它是个由官方规定出来的、用于「什么也不返回」的场景的返回值类型。但这只是它被规定的用法而已,而本质上它真就是个实实在在的类型
也就是在 Kotlin 里,并不存在真正没有返回值的函数,所有「没有返回值」的函数实质上的返回值类型都是 Unit,而返回值也都是 Unit 这个单例对象,这是 Unit 和 Java 的 void 在本质上的不同。

4. Unit 的价值所在

意义就在于,Unit 去掉了无返回值的函数的特殊性,消除了有返回值和无返回值的函数的本质区别,这样很多事做起来就会更简单了。
比如在 Java 里面,由于 void 并不是一种真正的类型,所以任何有返回值的方法在子类里的重写方法也都必须有返回值,而不能写成 void,不管你用不用泛型都是一样的:

public abstract class Maker {
  public abstract Object make();
}

public class AppleMaker extends Maker {
  // 合法
  @Override
  public Apple make() {
    return new Apple();
  }
}

public class NewWorldMaker extends Maker {
  // 非法
  @Override
  public void make() {
    world.refresh();
  }
}

泛型:

public abstract class Maker<T> {
  public abstract T make();
}

public class AppleMaker extends Maker<Apple> {
  // 合法
  Override
  public Apple make() {
    return new Apple();
  }
}

public class NewWorldMaker extends Maker<void> {
  // 非法
  Override
  public void make() {
    world.refresh();
  }
}

你只能去写一行 return null 来手动实现接近于「什么都不返回」的效果:

public class NewWorldMaker extends Maker {
  @Override
  public Object make() {
    world.refresh();
    return null;
  }
}

而且如果你用的是泛型,可能还需要用一个专门的虚假类型来让效果达到完美:

public class NewWorldMaker extends Maker<Void> {
  @Override
  public Void make() {
    world.refresh();
    return null;
  }
}

而在 Kotlin 里,Unit 是一种真实存在的类型,所以直接写就行了(这里还借助了Kotlin自动补上Unit类型 和 最后一行自动返回Unit单例对象):

abstract class Maker {
  abstract fun make(): Any
}

class AppleMaker : Maker() {
  override fun make(): Apple {
    return Apple()
  }
}

class NewWorldMaker : Maker() {
  override fun make() {
    world.refresh()
  }
}

泛型:

abstract class Maker<T> {
  abstract fun make(): T
}

class AppleMaker : Maker<Apple>() {
  override fun make(): Apple {
    return Apple()
  }
}

class NewWorldMaker : Maker<Unit>() {
  override fun make() {
    world.refresh()
  }
}

这就是 Unit 的去特殊性,或者说通用性所给我们带来的便利。

5. 延伸:当做纯粹的单例对象来使用

所以如果你什么时候想「随便拿个对象过来」,或者「随便拿个单例对象过来」,也可以使用 Unit,它和你自己创建一个 object 然后去使用,效果是一样的。


参考文章:
Unit 为啥还能当函数参数?面向实用的 Kotlin Unit 详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值