什么是关于何时,应该或不应该定义用户定义的隐式转换的一般指导原则?
我的意思是,例如,"隐式转换永远不会丢失信息","隐式转换永远不应该抛出异常",或"隐式转换永远不应该实例化新对象".我很确定第一个是正确的,第三个不是(或者我们只能隐式转换为结构),而我不知道第二个.
常见的Enrich-My-Library模式似乎是这样的
class Foo(value: Int)
implicit def int2Foo(i: Int) = new Foo(i)
Run Code Online (Sandbox Code Playgroud)
为什么不能implicit像这样只添加到构造函数本身
class Foo implicit (value: Int)
Run Code Online (Sandbox Code Playgroud)
考虑到构造函数不仅仅是一个带有一些额外限制的方法?
令人惊讶的是,以下确实有效:
class Foo(value: Int) {
implicit def this(a: String) = this(a.toInt)
}
Run Code Online (Sandbox Code Playgroud) 我尝试实现一些数字类型,我遇到了问题
mynum * 1
Run Code Online (Sandbox Code Playgroud)
有效,但不是
1 * mynum
Run Code Online (Sandbox Code Playgroud)
我试图定义这样的隐式转换
case class Num(v: Int) {
def * (o: Int) = new Num(v*o)
}
implicit def int2Num(v: Int) = Num(v)
Run Code Online (Sandbox Code Playgroud)
但它似乎不起作用,因为我总是得到以下错误:
scala> 1 * new Num(2)
<console>:14: error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (Num)
1 * new Num(2)
^
Run Code Online (Sandbox Code Playgroud)
另一方面
1 * BigInt(1)
Run Code Online (Sandbox Code Playgroud)
虽然我在查看代码时无法确定解决方案,但仍然有办法.
使其运作的机制是什么?
编辑:我用我遇到的实际问题创建了一个新问题, …
考虑以下非常简单的代码:
class A(val a: String, val b: Int)
object Test {
implicit class wrap(obj: A) {
def fn = obj.a + obj.b
}
def main(args: Array[String]) =
println(new A("Hello", 1).fn)
}
Run Code Online (Sandbox Code Playgroud)
反汇编代码产生:
public void main(java.lang.String[]);
Code:
0: getstatic #29; //Field scala/Predef$.MODULE$:Lscala/Predef$;
3: aload_0
4: new #31; //class A
7: dup
8: ldc #33; //String Hello
10: iconst_1
11: invokespecial #36; //Method A."<init>":(Ljava/lang/String;I)V
14: invokevirtual #38; //Method wrap:(LA;)LTest$wrap;
17: invokevirtual #42; //Method Test$wrap.fn:()Ljava/lang/String;
20: invokevirtual #46; //Method scala/Predef$.println:(Ljava/lang/Object;)V
23: return
Run Code Online (Sandbox Code Playgroud)
当 …
假设我有几个功能:
func1 : A => B
func2: B => C
func3: C => D
Run Code Online (Sandbox Code Playgroud)
我想在需要时以通用方式协调功能。
假设我需要从转换为A,然后B致电func1。但是,当我需要从转换为时A,D我希望将这些功能组合在一起。这样的事情在动态的观念中可能吗?
Object o = new Student(); // Implicit casting
我非常了解这段代码,而且我理解的是引用变量"o"是指"Object"类型的数据,我们可以看到Student从"Object"扩展,这意味着它引用了Student的一个实例.如果我写了以下代码:
Object x = o;
这会将o中的值分配给x,这意味着如果我们遵循x的方向,我们将转到上面的学生对象!
我的问题是,为什么我不能写下面的代码?:
Student x = o;
Run Code Online (Sandbox Code Playgroud)
"o"指的是"对象"类型的对象,该对象将其地址(在内存中)分配为"o",为什么我们不能将保存在o中的值分配给x!
我阅读了很多教程,CFLAGS并查看了官方文档.他们所说的任何地方CFLAGS都是隐式的,但仍然在它们的示例makefile中明确地将它传递给编译器:
CFLAGS=-O2
gcc $(CFLAGS) -c foo.c -o foo.o
Run Code Online (Sandbox Code Playgroud)
那么,"隐含"一词在这种背景下意味着什么呢?如果我CFLAGS=-O2在我的makefile中声明,稍后再说gcc -c foo.c -o foo.o,是否-O2会激活(那么,它是否真的隐含)?如果是这样,为什么所有教程(包括官方文档)仍然在他们的示例中明确地传递它?
代码:
object Test {
import scala.language.implicitConversions
case class C1() {}
case class C2() {}
implicit def c1ToC2(in: C1): C2 = C2()
def from[A, B](in: A)(implicit f: A => B): B = f(in)
def fails(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(from) // this line fails to compile!
}
def compiles1(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(x => from(x))
}
def compiles2(): Future[C2] = {
val future: Future[C1] = Future.successful(C1())
future.map(from[C1, C2])
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,只有该fails …
我在Scala中实现了以下代码
trait Implicit[A,B] { def method1(a:A, b:B) : Boolean }
object Implicit {
implicit object IntImplicit extends Implicit[Int,Int] {
override def method1(a: Int, b: Int): Boolean = a == b
}
}
object Main
{
def main(args:Array[String]) : Unit =
{
println(test(4,3))
}
def test[A,B](a:A, b:B)(implicit i: Implicit[A,B]) : Boolean =
i.method1(a,b)
}
Run Code Online (Sandbox Code Playgroud)
它实际上工作正常.但是,如果我定义以下功能
def jump[A,B](a:A, b:B) : Boolean = test(a,b)
Run Code Online (Sandbox Code Playgroud)
进入Main对象,它告诉我没有"足够的方法测试参数".我想这是因为它无法在编译时定义实际的隐式值.是真的还是问题不是别的什么?如果是,我该如何解决这个问题?
显然,这只是问题的简化,以便复制一个条件,我必须调用一个方法来声明一个先前不知道实际类型的隐式参数.
我有一个typeclass Search,Search[A]如果我们有个TypeClass1[A]或一个TypeClass2[A]实例,则有一个实例。优先考虑1实例。
编译如下:
trait TypeClass1[A]
trait TypeClass2[A]
trait Search[A]
object Search extends LPSearch {
implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
}
trait LPSearch {
implicit def case2[A](implicit ev: TypeClass2[A]): Search[A] = null
}
object Test {
implicit val ev1: TypeClass1[Int] = null
implicit val ev2: TypeClass2[Int] = null
implicitly[Search[Int]]
}
Run Code Online (Sandbox Code Playgroud)
就像我期望的那样,隐式搜索finds case1,finds ev1并停止搜索。
但是,如果我们更改TypeClass2为具有更多结构,则隐式搜索将停止工作:
trait TypeClass1[A]
trait TypeClass2[M[_], A]
trait Search[A]
object Search extends LPSearch …Run Code Online (Sandbox Code Playgroud)