为什么在Scala中可以使用这样的运算符定义?
发布时间:2020-12-16 08:51:10 所属栏目:安全 来源:网络整理
导读:我使用F#并不太了解 Scala,除了这些语言之间经常有一些相似之处.但是在Scala中查看Akka Streams实现时,我注意到使用了operator~以这种方式在F#中是不可能的(不幸的是).我不是在谈论只能在一元运算符开头的F#中使用的符号“?”,这并不重要.令我印象深刻的是定
我使用F#并不太了解
Scala,除了这些语言之间经常有一些相似之处.但是在Scala中查看Akka Streams实现时,我注意到使用了operator~>以这种方式在F#中是不可能的(不幸的是).我不是在谈论只能在一元运算符开头的F#中使用的符号“?”,这并不重要.令我印象深刻的是定义这样的图形的可能性:
in ~> f1 ~> bcast ~> f2 ~> merge ~> f3 ~> out bcast ~> f4 ~> merge 由于各种图形元素具有不同的类型(源,流,接收器),因此无法在F#中定义可以跨越它们的单个运算符.但我想知道为什么在Scala中这是可能的 – 这是因为Scala支持方法函数重载(而F#不支持)? UPDATE. Fydor Soikin在F#中展示了几种重载方式,可以用来在使用F#时实现类似的语法.我试过这个,这里看起来如何: type StreamSource<'a,'b,'c,'d>(source: Source<'a,'b>) = member this.connect(flow : Flow<'a,'d>) = source.Via(flow) member this.connect(sink: Sink<'a,Task>) = source.To(sink) type StreamFlow<'a,'c>(flow : Flow<'a,'c>) = member this.connect(sink: Sink<'b,Task>) = flow.To(sink) type StreamOp = StreamOp with static member inline ($) (StreamOp,source: Source<'a,'b>) = StreamSource source static member inline ($) (StreamOp,flow : Flow<'a,'c>) = StreamFlow flow let inline connect (a: ^a) (b: ^b) = (^a : (member connect: ^b -> ^c) (a,b)) let inline (>~>) (a: ^a) (b: ^b) = connect (StreamOp $a) b 现在我们可以编写以下代码: let nums = seq { 11..13 } let source = nums |> Source.From let sink = Sink.ForEach(fun x -> printfn "%d" x) let flow = Flow.FromFunction(fun x -> x * 2) let runnable = source >~> flow >~> sink 解决方法
实际上,Scala至少有四种不同的方法可以使它工作.
(1)方法重载. def ~>(f: Flow) = ??? def ~>(s: Sink) = ??? (2)继承. trait Streamable { def ~>(s: Streamable) = ??? } class Flow extends Streamable { ... } class Sink extends Streamable { ... } (3)类型和类似的通用结构. def ~>[A: Streamable](a: A) = ??? (使用Streamable [Flow],Streamable [Sink],…提供所需功能的实例). (4)隐含转换. def ~>(s: Streamable) = ??? (使用隐式def flowCanStream(f:Flow):Streamable = ???等). 每个都有自己的优点和缺点,所有这些都在各种库中大量使用,尽管最后因为太容易产生意外而有些失宠.但要拥有你所描述的行为,其中任何一种都可行. 在实践中,在Akka Streams中,它实际上是我能说的1-3的混合物. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |