官术网_书友最值得收藏!

Default parameters

Sometimes, it is convenient to provide default values for parameters in a function. Let's say that we want to create a thread pool. The parameter to set the number of threads could default to the number of CPU cores. This would be a sensible default, but the user might still want to use something different.

The way to achieve this in languages without default parameters is to offer overloaded versions of the same function:

    fun createThreadPool(): ExecutorService { 
      val threadCount = Runtime.getRuntime().availableProcessors() 
      return createThreadPool(threadCount) 
    } 
 
    fun createThreadPool(threadCount: Int): ExecutorService { 
      return Executors.newFixedThreadPool(threadCount) 
    } 

Here, the user can now choose which version to invoke. However, the number of parameters sometimes means that we end up with many overloaded variations of the same function, resulting in needless boilerplate. For example, the Java BigDecimal standard library has the following functions:

    public BigDecimal divide(BigDecimal divisor) 
 
    public BigDecimal divide(BigDecimal divisor, RoundingMode  roundingMode)
    public BigDecimal divide(BigDecimal divisor, int scale,  RoundingMode roundingMode)

There are many other variations. Each function just delegates to the next one with a sensible default.

In Kotlin, a function can define one or more of its parameters to have default values, which are used if the arguments are not specified. This allows a single function to be defined for several use cases, thereby avoiding the need for multiple overloaded variants.

Here is the divide function again, but this time, by using default parameters, we can reduce the definition to a single function:

    fun divide(divisor: BigDecimal, scale: Int = 0, roundingMode:  RoundingMode = RoundingMode.UNNECESSARY): BigDecimal

When invoking this function, we can omit some or all of the parameters, but once a parameter is omitted, all the following parameters must be omitted as well. For instance, we could invoke this function in the following ways:

    divide(BigDecimal(12.34)) 
    divide(BigDecimal(12.34), 8) 
    divide(BigDecimal(12.34), 8, RoundingMode.HALF_DOWN) 

Each of the previous examples call the same method, but where a parameter has been omitted, the default value from the function definition is inserted. In other words, the previous example is exactly the same as the following:

    divide(BigDecimal(12.34), 0, RoundingMode.UNNECESSARY) 
    divide(BigDecimal(12.34), 8, RoundingMode.UNNECESSARY) 
    divide(BigDecimal(12.34), 8, RoundingMode.HALF_DOWN) 

However, the following would not be legal:

    divide(BigDecimal(12.34), RoundingMode.HALF_DOWN) 

To solve this problem, we can mix named parameters and default parameters:

    divide(BigDecimal(12.34), roundingMode = RoundingMode.HALF_DOWN) 

In general, using named parameters in combination with default parameters is very powerful. It allows us to provide one function, and users can selectively override the defaults they wish.

When overriding a function that declares default parameters, we must keep the same function signature.

Default parameters can also be used in constructors to avoid the need for multiple secondary constructors. The following example shows multiple constructors:

    class Student(val name: String, val registered: Boolean, credits:  Int) { 
      constructor(name: String) : this(name, false, 0) 
      constructor(name: String, registered: Boolean) : this(name,  registered, 0) 
    } 

These constructors can be rewritten as the following:

    class Student2(val name: String, val registered: Boolean = false,  credits: Int = 0)

Let's now learn about extension functions.

主站蜘蛛池模板: 寿阳县| 宁乡县| 肥乡县| 江川县| 汉中市| 济宁市| 孝义市| 榆中县| 普陀区| 枝江市| 玛纳斯县| 本溪市| 灵璧县| 高青县| 汶川县| 南丹县| 南江县| 兰州市| 江口县| 长白| 达尔| 肃北| 宝坻区| 额尔古纳市| 师宗县| 长沙县| 双桥区| 临沭县| 文安县| 小金县| 寿阳县| 龙口市| 玉门市| 广东省| 梅州市| 萍乡市| 陈巴尔虎旗| 西乡县| 哈尔滨市| 彭州市| 隆化县|