我想实现一个无限的列表:
abstract class MyList[+T]
case object MyNil extends MyList[Nothing]
case class MyNode[T](h:T,t: => MyList[T]) extends MyList[T]
//error: `val' parameters may not be call-by-name
Run Code Online (Sandbox Code Playgroud)
问题是call-by-name不允许的.
我听说这是因为val或者var不允许使用构造函数参数call-by-name.例如:
class A(val x: =>Int)
//error: `val' parameters may not be call-by-name
Run Code Online (Sandbox Code Playgroud)
但矛盾的是,正常的构造函数的参数仍然是val,尽管private.例如:
class A(x: =>Int)
// pass
Run Code Online (Sandbox Code Playgroud)
所以问题是:
val还是var?
call-by-name或val计算(或初始化)被推迟?由于我理解call-by-name了方法的参数,因此在将参数表达式传递给方法时,不会计算相应的参数表达式,但只有在方法体中使用参数的值时(以及如果).
但是,在下面的例子中,这只在前两个方法调用中才有效,但在第三个方法调用中不是这样,尽管它应该只是第二种情况的语法变体!
为什么在第三个方法调用中计算参数表达式?
(我使用Scala 2.11.7测试了此代码)
class Node(x: => Int)
class Foo {
def :: (x: =>Int) = new Node(x) // a right-associative method
def !! (x: =>Int) = new Node(x) // a left-associative method
}
// Infix method call will not evaluate a call-by-name parameter:
val node = (new Foo) !! {println(1); 1}
println("Nothing evaluated up to here")
// Right-associative method call will not evaluate a call-by-name parameter:
val node1 = (new Foo).::({println(1); 1})
println("Nothing evaluated up to …Run Code Online (Sandbox Code Playgroud) 在我的编程类原则中,我们讨论的是不同的调用方法.我们讨论的一些是:
我无法找到名称调用如何工作的示例.有人在乎给我一个例子吗?我认为当你将xml文件作为输入时,这类似于按名称调用.有人能给我一个更传统的例子吗?
我最近一直在关注各种scala日志库,其中绝大多数都实现了日志记录功能
def debug(s: => String)
Run Code Online (Sandbox Code Playgroud)
因此,如果关闭调试日志记录,它将不会执行该语句.但是,我刚刚遇到了logula,它特别指出了它的一个好处
对于其记录语句,这意味着两两件事:不像很多Scala的记录库,Logula不使用通过按姓名语义(=>阿例如,f):
- Scala编译器不必为每个日志记录语句创建一次性闭包对象.这应该减少垃圾收集压力.
这实际上对我来说是完全合理的.所以我的问题是,是否存在比较这两种方法的真实世界性能基准/数据?理想情况下,从现场项目到人为的基准测试?
这里有两个似乎被普遍接受的陈述,但我无法真正克服:
1)Scala的副名称params优雅地替换了令人讨厌的log4j使用模式:
if (l.isDebugEnabled() ) {
logger.debug("expensive string representation, eg: godObject.toString()")
}
Run Code Online (Sandbox Code Playgroud)
因为在方法调用之前不会评估by-name-parameter(特定于Scala的语言特性).
2)但是,这个问题是通过slf4f中的参数化日志记录解决的:
logger.debug("expensive string representation, eg {}:", godObject[.toString()]);
Run Code Online (Sandbox Code Playgroud)
那么,这是如何工作的?在"调试"方法执行之前,slf4j库中是否存在一些阻止参数评估的低级魔法?(甚至可能吗?图书馆可以影响语言的这一基本方面吗?)
或者只是一个简单的事实,一个对象被传递给方法 - 而不是一个字符串?(并且可能在debug()方法本身中调用该对象的toString()(如果适用).
但那么,log4j也不是这样吗?(它确实有Object params的方法).这不意味着如果你传递一个字符串 - 如上面的代码 - 它的行为与log4j相同吗?
我真的很想在这个问题上有一些亮点.
谢谢!
我希望能够模拟getOrElse方法的返回值,以便它返回orElse使用ScalaMock 作为call-by-name参数传递的内容
trait ToBeMocked {
def getOrElse(arg: Int)(orElse: => String): String
}
Run Code Online (Sandbox Code Playgroud)
由于currying,必须使用ScalaMock.运行这个:
class CallByNameMockSpec extends Specification with MockFactory {
trait ToBeMocked {
def getOrElse(arg: Int)(orElse: => String): String
}
"Mocking functions with call-by-name arguments" should {
"work" in {
val m = mock[ToBeMocked]
(m.getOrElse (_: Int)(_: String)).expects(101, *).onCall((x, y) => y)
m.getOrElse(101)("result") must beEqualTo("result")
}
}
}
Run Code Online (Sandbox Code Playgroud)
抛出异常:
[error] ClassCastException:
test.service.CallByNameMockSpec$$anonfun$1$$anonfun$apply$1$$anonfun$apply$3$$anonfun$apply$4 cannot be cast to java.lang.String (CallByNameMockSpec.scala:16)
Run Code Online (Sandbox Code Playgroud) 我们来看下面的代码:
import scala.language.implicitConversions
class Foo
implicit def int2Foo(a: => Int): Foo = new Foo
def bar(foo: Foo) = {}
def bar(foo: Boolean) = {}
bar {
println("Hello")
64
}
Run Code Online (Sandbox Code Playgroud)
此代码不显示任何信息,因为该块包含println("Hello")被视为=> Int它转化为Foo通过int2Foo.但是如果省略重载函数,就会发生令人惊讶的事情bar(foo: Boolean)
import scala.language.implicitConversions
class Foo
implicit def int2Foo(a: => Int): Foo = new Foo
def bar(foo: Foo) = {}
bar {
println("Hello")
64
}
Run Code Online (Sandbox Code Playgroud)
这会打印,Hello因为它会对块进行求值,64在这种情况下,只有最后一个语句被视为按名称调用参数.我无法理解这种差异背后存在什么样的理由.
我目前正在使用CallByName来动态调用方法.我每天从服务器中的表中提取几种方法以及参数.出于这个原因,我将一个参数数组发送到CallByName而不是一个param数组,因为我不知道运行时的参数数量.鉴于CallByName需要一个paramarray,我使用私有声明函数来绕过VBA类型定义.
Private Declare PtrSafe Function rtcCallByName Lib "VBE7.DLL" ( _
ByVal Object As Object, _
ByVal ProcName As LongPtr, _
ByVal CallType As VbCallType, _
ByRef Args() As Any, _
Optional ByVal lcid As Long) As Variant
Public Function CallByNameMethod(Object As Object, ProcName As String, ByRef Args () As Variant)
AssignResult CallByNameMethod, rtcCallByName(Object, StrPtr(ProcName), VbMethod, Args)
End Function
Private Sub AssignResult(target, Result)
If VBA.IsObject(Result) Then Set target = Result Else target = Result
End Sub
Run Code Online (Sandbox Code Playgroud)
当我传递方法更改其基础属性的对象时,这种方法有效.但是,有一些方法可以传递一个对象和一个更改传递参数值的方法.例如,我传递一个带有以下参数的数组
Dim Name as String, …Run Code Online (Sandbox Code Playgroud)
在Perl中,您可以通过引用(或名称)调用函数,如下所示:
my $functionName = 'someFunction';
&$functionName();
#someFunction defined here:
sub someFunction { print "Hello World!"; }
Run Code Online (Sandbox Code Playgroud)
我想要做的是使用哈希值,如下所示:
my %hash = (
functionName => 'someFunction',
);
&$hash{functionName}();
#someFunction defined here:
sub someFunction { print "Hello World!"; }
Run Code Online (Sandbox Code Playgroud)
我得到的错误是全局符号"$ hash"需要显式包名.
我的问题是:没有使用中间变量有没有正确的方法来做到这一点?
任何有关这方面的帮助将不胜感激!
def getStr(): String = {
println("getStr is running")
"str"
}
def lazyHello(para: => String) = {
println("lazy hello is runing")
println(para)
}
def notLazyHello(para: String) = {
println("not lazy hello is runing")
println(para)
}
def anoyHello(para: () => String) = {
println("anoy hello is runing")
println(para())
}
notLazyHello(getStr)
lazyHello(getStr)
anoyHello(getStr)
Run Code Online (Sandbox Code Playgroud)
得到了这个结果:
scala> notLazyHello(getStr)
getStr is running
not lazy hello is runing
str
scala> lazyHello(getStr)
lazy hello is runing
getStr is running
str
scala> anoyHello(getStr)
anoy hello is runing
getStr is …Run Code Online (Sandbox Code Playgroud) scala anonymous-function lazy-evaluation callbyname call-by-value
callbyname ×10
scala ×7
dynamic ×1
hash ×1
logging ×1
marshalling ×1
mocking ×1
performance ×1
perl ×1
reference ×1
slf4j ×1
subroutine ×1
theory ×1
vba ×1