我有一个函数,它的确切行为由一组标志控制。其中大部分通常是错误的。将它们全部作为参数很快就会变得非常混乱。
我可以为标志创建一个枚举:
enum ParseFlags { assignmentPossible = 1, commaDelimits = 2, isConst = 4 };
PExpression ParseExpr(unsigned int flags);
Run Code Online (Sandbox Code Playgroud)
好一点:现在,在调用函数时,我只需指定要设置的值,而不是一长串bools。
但是,我想知道是否有更优雅或更通用的方法将选项子集传递给函数。如果我有非布尔选项怎么办?
我正在寻找一种 C++(Boost 可以)方式来调用如下函数:
ParseExpr({ isConst: true; maxDepth: 5 });
Run Code Online (Sandbox Code Playgroud)
我可以省略我想保留默认值的所有值。
为此存在哪些技术和/或库?
我正在尝试链接Iterators:
var it = Iterator(1)
it.next
it = Iterator(2) ++ it
it.next
it.hasNext
Run Code Online (Sandbox Code Playgroud)
hasNext正如您在此处看到的那样无限循环:https : //scastie.scala-lang.org/qbHIVfsFSNO5OYmT4pkutA
如果您运行它并在无限循环时检查堆栈,它会在内容中循环:
at scala.collection.Iterator$ConcatIterator.merge(Iterator.scala:213)
at scala.collection.Iterator$ConcatIterator.advance(Iterator.scala:197)
at scala.collection.Iterator$ConcatIterator.hasNext(Iterator.scala:227)
Run Code Online (Sandbox Code Playgroud)
(此堆栈来自 Scala 2.12.11,但 Scastie 链接在 中显示相同的行为2.13.2)。
我知道在调用方法之后永远不应该使用迭代器,但这似乎对我有用。使用varto 指向“当前”迭代器并将其更改为指向一个新的迭代器,该迭代器附加上一个迭代器的剩余部分。
以下稍微修改确实有效:
at scala.collection.Iterator$ConcatIterator.merge(Iterator.scala:213)
at scala.collection.Iterator$ConcatIterator.advance(Iterator.scala:197)
at scala.collection.Iterator$ConcatIterator.hasNext(Iterator.scala:227)
Run Code Online (Sandbox Code Playgroud)
Scastie 链接:https ://scastie.scala-lang.org/1X0jslb8T3WIFLHamspYAg
这向我表明,以某种方式损坏的版本正在创建一个附加自身的迭代器。关于这里发生了什么的任何提示?
下面(设计的)代码尝试在将来打印一个名字的String参数,并在打印完成时返回.
import scala.concurrent._
import concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
class PrintValueAndWait {
def printIt(param: => String): Unit = {
val printingComplete = future {
println(param); // why does this hang?
}
Await.result(printingComplete, Duration.Inf)
}
}
object Go {
val str = "Rabbits"
new PrintValueAndWait().printIt(str)
}
object RunMe extends App {
Go
}
Run Code Online (Sandbox Code Playgroud)
但是,在运行时RunMe,它只是在尝试评估时挂起param.更改printIt为接受其参数的值会使应用程序按预期返回.或者,更改printIt为简单地打印值并同步返回(在同一个线程中)似乎也可以正常工作.
这到底发生了什么?这是否与Go对象有关尚未完全构造,因此该str字段尚未显示给尝试打印它的线程?挂在这里的预期行为?
我已经在Java 1.7上使用Scala 2.10.3在Mac OS Mavericks和Windows 7上进行了测试.
我希望在执行之前按名称传递一个函数.请考虑以下示例:
class Runner {
def apply(procedure: => Unit) = {
println("running procedure")
procedure
}
}
new Runner()(println("procedure!")) // #1
new Runner(){println("procedure!")} // #2
Run Code Online (Sandbox Code Playgroud)
调用#1和#2之间的唯一区别在于花括号.而第一次通话输出
running procedure
procedure!
Run Code Online (Sandbox Code Playgroud)
正如所料,仅在第二次通话中
procedure!
Run Code Online (Sandbox Code Playgroud)
打印出来.
似乎在使用花括号时,程序不是通过名称传递,而是执行.为什么在这个例子中,卷曲和圆括号不可互换?
来自我的另一个问题 是有一种方法来获取构造函数的名字参数吗?我需要一种方法来提供一个代码块,它在对象内部按需/延迟/按名称执行,这个代码块必须能够访问类方法,就像代码块是类的一部分一样.
以下Testcase失败:
package test
class ByNameCons(code: => Unit) {
def exec() = {
println("pre-code")
code
println("post-code")
}
def meth() = println("method")
def exec2(code2: => Unit) = {
println("pre-code")
code2
println("post-code")
}
}
object ByNameCons {
def main(args: Array[String]): Unit = {
val tst = new ByNameCons {
println("foo")
meth() // knows meth() as code is part of ByNameCons
}
tst.exec() // ByName fails (executed right as constructor)
println("--------")
tst.exec2 { // ByName works
println("foo")
//meth() // does not …Run Code Online (Sandbox Code Playgroud) 这是一个重新开放的问题.
我寻找一种语言和支持平台,默认情况下语言可以通过引用传递或按名称传递语义.我知道历史有点,有Algol,Fortran,还有C++可以使它成为可能; 但是,基本上,我所寻找的是更现代的东西,并且提到的值传递方法是首选的并且默认情况下(隐式假设).
我问这个问题,因为在我看来,pass-by-ref/name的一些优点似乎很明显.例如,当它在独立代理中使用时,不需要(在某种程度上)值的值,并且在这种情况下性能不会降低很多.所以,我可以在例如富客户端应用程序或某些游戏风格或独立服务类应用程序中使用它.
对我来说,主要的优点是符号的身份与其当前值之间的明确分离.我的意思是,当没有复制复制时,您知道您正在使用您查询/接收的确切符号/路径.并且内在的拳击值不会干扰程序的实际逻辑.
我知道有C#ref关键字,但它不是那么内向,虽然可以接受.同样地,我意识到传递引用语义几乎可以用任何语言模拟(Java作为一个例子)等等......不确定传递名称:)
你会建议什么 - 在适当的地方创建类似DSL的东西来满足这些需求; 或者使用我已经知道的一些语言?也许,有些东西我不见了?
谢谢!
更新:目前,我认为Haskell是合适的.但我没有多少调查,所以我想我稍后会更新这个文本.
Scala Tour Of Scala 文档以 whileLoop 函数为例解释了按名称传递的参数。
def whileLoop(condition: => Boolean)(body: => Unit): Unit =
if (condition) {
body
whileLoop(condition)(body)
}
var i = 2
whileLoop (i > 0) {
println(i)
i -= 1
} // prints 2 1
Run Code Online (Sandbox Code Playgroud)
该部分解释了如果不满足条件,则不会评估主体,从而通过不评估未使用的代码主体来提高性能。
Scala 的实现是否while已经使用了按名称传递的参数?
如果有原因或特定情况导致实现无法使用按名称传递参数,请向我解释,到目前为止我还没有找到任何相关信息。
编辑:根据 Valy Dia(/sf/users/407844461/)的回答,我想添加另一个问题......
如果在某些情况下可能根本不评估主体,while 语句的方法实现是否会比语句本身性能更好?如果是这样,为什么要使用 while 语句呢?
我将尝试对此进行测试,但我是 Scala 的新手,因此可能需要一些时间。如果有人愿意解释,那就太好了。
干杯!
pass-by-name ×7
scala ×5
c++ ×1
constructor ×1
flags ×1
future ×1
mutability ×1
object ×1
while-loop ×1