除去Scala的糖衣(13) -- Default Parameter Value

欢迎关注我的新博客地址:http://cuipengfei.me/

 

好久没有写博客了,上一次更新居然是一月份。

说工作忙都是借口,咋有空看美剧呢。

这半年荒废掉博客说究竟就是懒,惯性的懒惰。写博客这事儿,一丢掉就非常久捡不起来。

闲话到此为止。以下进入正题。

Default parameter value,默认參数值。 这个非常easy理解,给參数一个默认值,假设调用者不显式指明參数值。则使用默认值。

假设显式指明了,那就用显式指明的值。

举个样例:

1
def hello(name: String = "world") = println("hello " + name) 

这个函数。假设我们不给它传參数,它就会打印hello world。

就像这样:

1
hello()

假设给了參数:

1
hello("everybody") 

则打印hello everybody。

这个语言特性都有哪些应用场景呢?

它经经常使用来避免过多的重载。

一个非经常见非常典型的样例就是构造函数重载。

在Java中,为了让调用者可以比較easy的创建某个类的实例。我们一般会提供几个參数列表比較短的构造函数。而这些构造函数存在的唯一意义就是为了写死某几个參数值。而在Scala中。有了这个语言特性,我们就无需那么麻烦了。

那这个语言特性是怎样实现的呢?实际上简单的一塌糊涂。

这样一段代码:

1
2
3
4
5
6 7 
class Greeter {
 def hello(name: String = "world") = println("hello " + name) }  class AnotherClass {  new Greeter().hello() } 

我们的Greeter类含有前面提到过的hello方法。在AnotherClass里调用了hello,而且没有显式指明參数值。

上面的Scala代码生成的bytecode反编译成Java是这种:

1
2
3
4
5
6 7 8 9 10 11 12 13 14 15 16 17 
public class Greeter {  public void hello(String name) {  Predef..MODULE$.println(new StringBuilder().append("hello ").append(name).toString());  }   public String hello$default$1() {  return "world";  } }  public class AnotherClass {  public AnotherClass() {  Greeter qual$1 = new Greeter();  String x$1 = qual$1.hello$default$1();  qual$1.hello(x$1);  } } 

能够看到,我们所定义的hello方法反编译出来看起来非常普通,就是个接受一个參数的方法。

而在Greeter类中,编译器为我们增加了还有一个方法hello$default$1,这种方法就是返回一个写死的字符串,其值为world。

在AnotherClass中调用hello时,写死的字符串被取到。然后传进了hello里。

这样。被调用者提供了參数的默认值,调用者在调用时取得该值,然后传入方法。

题外话

到这里我不禁联想起C#中的默认參数值的实现方式。

在C#中。默认參数的值会被编译成调用者的一个常量,而不是像Scala一样的由被调用者提供。

这样看起来貌似没啥差别,不就是写死的值换个地方吗?

事实上不然,假设被调用者在A程序集内,调用者在B程序集内,那么A更新时,B就必须又一次编译才干得到最新的默认值。也就是说,假设当前部署环境中同一时候存在A和B。而后我们拿一个新版的A来替换老的,这时B仍然在传递老的默认參数值给A。这样就会造成一些看似非常诡异的行为偏差。

假设对C#的默认參数值的实现有兴趣。请看我非常久非常久之前写的博客

如今想来,C#这一语言特性的设计者为什么要把它设计成如此easy出错的样子呢?

思而不得其解。

转载于:https://www.cnblogs.com/lxjshuju/p/6860901.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shapley-Value是一种用于解决合作博弈中成员收益分配问题的方法。在Scala中,可以通过以下步骤来实现Shapley-Value的计算: 1. 定义一个表示玩家的类,包括以下属性:名称、对其他玩家的贡献函数、玩家的价值。 2. 定义一个表示游戏的类,包括以下属性:玩家列表、游戏收益函数。 3. 实现Shapley-Value的计算方法,该方法接受一个游戏对象和一个玩家名称作为参数。该方法通过对每个玩家进行排列组合,计算每个玩家在不同的联合决策中的贡献,并将其加权平均,得出该玩家的Shapley-Value。 下面是一个简单的Scala实现: ```scala case class Player(name: String, contribution: List[Int], value: Int) class Game(val players: List[Player], val payoffFunction: List[Int] => Int) { def shapleyValue(playerName: String): Double = { val player = players.find(_.name == playerName).get val n = players.length val permutations = (1 to n-1).flatMap(i => (0 to n-2).combinations(i)) val contributions = permutations.map { indices => val subset = players.filter(p => indices.contains(players.indexOf(p))) val subsetPayoffFunction = (list: List[Int]) => payoffFunction(indices.map(list(_))) subsetPayoffFunction(indices.map(player.contribution(_))).toDouble } contributions.sum / factorial(n) } private def factorial(n: Int): Int = if (n == 1 || n == 0) 1 else n * factorial(n-1) } ``` 在这个实现中,我们首先定义了一个Player类,其中包含玩家的名称、对其他玩家的贡献函数和玩家的价值。然后,我们定义了一个Game类,其中包含玩家列表和游戏收益函数。最后,我们实现了Shapley-Value的计算方法shapleyValue,该方法接受一个玩家名称作为参数,并返回该玩家的Shapley-Value。 在shapleyValue方法中,我们首先找到了要计算Shapley-Value的玩家。然后,我们使用排列组合的方法计算每个玩家在不同联合决策中的贡献,并将其加权平均得到该玩家的Shapley-Value。我们还实现了一个私有方法factorial,该方法计算阶乘,用于计算排列组合数。 注意:以上代码仅为示例,具体实现可能需要根据实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值