当被问及Scala中的依赖注入时,很多答案都指向使用Reader Monad,无论是来自Scalaz还是只是自己编写.有很多非常明确的文章描述了这种方法的基础知识(例如,Runar的演讲,Jason的博客),但我没有设法找到更完整的例子,我没有看到这种方法的优势超过例如更多传统的"手动"DI(参见我写的指南).最有可能的是我错过了一些重要的观点,因此问题就出现了.
举个例子,我们假设我们有这些类:
trait Datastore { def runQuery(query: String): List[String] }
trait EmailServer { def sendEmail(to: String, content: String): Unit }
class FindUsers(datastore: Datastore) {
def inactive(): Unit = ()
}
class UserReminder(findUser: FindUsers, emailServer: EmailServer) {
def emailInactive(): Unit = ()
}
class CustomerRelations(userReminder: UserReminder) {
def retainUsers(): Unit = {}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我使用类和构造函数参数进行建模,这与"传统"DI方法非常相似,但是这个设计有几个好的方面:
UserReminder
不知道FindUsers
需要数据存储.功能甚至可以在单独的编译单元中IO
如果我们想要捕获效果等,"业务逻辑"方法可以返回包含在monad中的值.怎么能用Reader monad建模呢?保留上面的特性会很好,因此很清楚每个功能需要什么样的依赖关系,并隐藏一个功能与另一个功能的依赖关系.请注意,使用class
es更多的是实现细节; 也许使用Reader monad的"正确"解决方案会使用其他东西.
我找到了一个有点相关的问题,暗示:
请考虑以下代码段:
trait X[-T]
object Y extends X[Nothing]
def a[T](x: X[T]): X[T] = x
a(Y)
Run Code Online (Sandbox Code Playgroud)
上述(2.12.3)的汇编失败了:
type mismatch;
found : Y.type
required: X[T]
a(Y)
^
Run Code Online (Sandbox Code Playgroud)
如果符合以下情况,这将编
Nothing
(例如object Y extends X[String]
)a
不在T
其返回类型中使用(例如def a[T](x: X[T]): Unit = {}
)a
明确给出了类型参数(即a[Nothing](Y)
)T
是协变的,而不是逆变的(如果它是不变的也会失败)这是编译器中的一些特例Nothing
吗?
作为一个"有趣"的解决方案,以下似乎工作正常:
trait X[-T]
object Y extends X[Nothing]
def a[T, U <: T](x: X[T]): X[U] = x
a(Y)
Run Code Online (Sandbox Code Playgroud) 我在解码电子邮件附件的文件名方面遇到了问题.目前我正在使用JavaMail 1.4.2.该文件名为"Żółw.rtf"(这是Turtle.rtf的润色).邮件是使用Mail.app发送的(这看起来非常重要).重要的标题是:
--Apple-Mail-19-721116558
Content-Disposition: attachment;
filename*=utf-8''Z%CC%87o%CC%81%C5%82w.rtf
Content-Type: text/rtf;
x-unix-mode=0644;
name="=?utf-8?Q?Z=CC=87o=CC=81=C5=82w=2Ertf?="
Content-Transfer-Encoding: 7bit
Run Code Online (Sandbox Code Playgroud)
相应的javax.mail.Part.getFileName()返回"=?utf-8?Q?Z = CC = 87o = CC = 81 = C5 = 82w = 2Ertf?=",在应用MimeUtility.decodeText后,它是: "ZÃáoÃÅ≈Çw.rtf".显然不是原来:).
为了比较,MimeUtility.encodeText返回:
=?UTF-8?Q?=C5=BB=C3=B3=C5=82w.rtf?=
Run Code Online (Sandbox Code Playgroud)
相比之下:
=?utf-8?Q?Z=CC=87o=CC=81=C5=82w=2Ertf?=
Run Code Online (Sandbox Code Playgroud)
来自电子邮件.
根据我的研究,字母"Ż"可以用两种方式编码:作为单个字母或"Z"+以上点.MimeUtility.encodeText使用前者,Mail.app使用后者.
但是我希望能够解码两者.有没有办法解码使用JavaMail从Mail.app发送的文件名?或者也许还有其他一些图书馆?
谢谢!亚当
例如,要获取宏的呼叫站点上的所有值及其类型?或者至少只是当前班级的价值?例如:
class A {
val v1 = 10
var v2 = "2"
def m {
val m3 = true
// Here I would like to get information that v1: Int, v2: String and
// v3: Boolean are available
macroInvocation()
}
}
Run Code Online (Sandbox Code Playgroud)
我查看了Context和Universe,但找不到好的方法.
到目前为止我找到的唯一解决方案是获取宏的封闭类/方法(通过Context),并搜索树.
任何函子都可以进行这样的转换,不仅是Future
:
implicit class RichFunctorReader[F[_]: Functor, A, B](fr: F[Reader[A, B]]) {
def toReaderFunctor: Reader[A, F[B]] = Reader { a => fr.map(_.run(a)) }
}
Run Code Online (Sandbox Code Playgroud)
我想知道这是Reader
monad 的特殊属性,还是有一个更通用的概念使之成为可能?
例如,当我们泛化为时Reader
,它就不起作用Kleisli
,因此我怀疑Reader
这里是“特殊情况”。
scala ×4
scalaz ×2
jakarta-mail ×1
java ×1
macos ×1
macros ×1
mime ×1
scala-2.10 ×1
scala-macros ×1