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

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.

主站蜘蛛池模板: 利辛县| 诸城市| 宁南县| 龙海市| 汕尾市| 绥滨县| 青阳县| 冷水江市| 静宁县| 布尔津县| 固始县| 桐柏县| 定安县| 佛冈县| 曲阜市| 屯门区| 吴堡县| 青浦区| 海兴县| 外汇| 株洲市| 洪江市| 丘北县| 达日县| 四子王旗| 阿鲁科尔沁旗| 乌审旗| 平阳县| 安义县| 宁阳县| 彝良县| 天镇县| 庆城县| 剑阁县| 开原市| 新疆| 桦甸市| 环江| 宝兴县| 渝中区| 渭南市|