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

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.

主站蜘蛛池模板: 高碑店市| 易门县| 汝州市| 林口县| 阳曲县| 科技| 建水县| 达州市| 信宜市| 宝丰县| 碌曲县| 来凤县| 永康市| 浦县| 五河县| 沙田区| 华亭县| 宝应县| 礼泉县| 周至县| 济南市| 聂荣县| 台安县| 泗水县| 资阳市| 高碑店市| 平湖市| 福建省| 江川县| 高台县| 磴口县| 龙海市| 安阳市| 松阳县| 乐至县| 蓬溪县| 香格里拉县| 嘉定区| 常德市| 金寨县| 鱼台县|