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

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.

主站蜘蛛池模板: 中阳县| 云南省| 拜城县| 漳浦县| 桂东县| 宜昌市| 南昌市| 利辛县| 枣庄市| 洮南市| 长子县| 离岛区| 合山市| 门头沟区| 金平| 乐陵市| 邓州市| 彩票| 河源市| 漠河县| 巴林右旗| 漾濞| 万年县| 偃师市| 织金县| 巢湖市| 西乡县| 苗栗县| 时尚| 密云县| 龙岩市| 汶上县| 额敏县| 呼玛县| 肇东市| 琼海市| 阜宁县| 乐都县| 天门市| 泸西县| 南丹县|