当我想切换功能和对象时,我可以使用scalaz
|>
运算符,这样可以获得更多的可读性。让我向您介绍一个模型函数:
def length2(x:String) = x.length * 2
现在,我可以用两种方式编写它:"aoeu" |> length2
length2("aoeu")
但是,如果我将此函数定义为更通用,它将停止工作。def length2(x:SeqLike[_
,_
]) = x.length * 2
length2("aoeu") // ok
"aoeu" |> length2 // doesn't work
为什么编译器不理解这个?肯定是从_
隐式转换为特质_
中的某个类混合。
答案 0 :(得分:12)
scala> "aoeu" |> length2
<console>:14: error: type mismatch;
found : (scala.collection.SeqLike[_, _]) => Int
required: (java.lang.String) => ?
"aoeu" |> length2
错误信息非常清楚。
虽然存在从String
到SeqLike[_,_]
的隐式转换,但无法从(SeqLike[_, _]) => Int
转换为String => ?
。
可以使用以下隐式转换修复此问题:
implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
def g(t:T) = f(t)
g _
}
编辑2 :这是一个非scalaz运算符。
class Pipe[T](t:T) {
def |%>[X, U](f: (X) => U)(implicit ev: T <%< X) = f(t)
}
implicit def toPipe[T](t:T) = new Pipe(t:T)
然后你可以像这样使用它:
def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2
"abc" |%> l1
"abc" |%> l2
只要有|%>
隐式转换的证据,{}允许T
执行直接在X
上工作但在T
上不起作用的函数到X
。
答案 1 :(得分:2)
除非必要,否则不要使用存在类型。他们破坏了东西,这里不需要。
另一方面,看到其他答案中的错误使事情变得更加清晰。当您使用|>
时,要求您进行两次隐式转换。如果你这样声明它是否有效:
def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2