要解决的两个主要问题:
1)类型检查丢失
使用数组参数Single.zip()
版本时,我丢失了强类型参数。
2)源参数不能为空
我无法将可为空的源值作为Single.zip()
函数的参数发送
3)我需要一个替代方法,该方法接受一个未键入的Object[]
:
4)我不想使用可变对象,我不想在类中使用var,我想使用瓦尔
public static <T, R> Single<R> zipArray(Function<? super Object[], ? extends R> zipper, SingleSource<? extends T>... sources) ...
在haskell中,有一个与How can I implement generalized "zipn" and "unzipn" in Haskell?相关的问题:
在haskell中,我可以用应用函子来实现这一点:
f <$> a1 <*> a2 <*> a3 <*> a4 <*> a5 <*> a6 <*> a7 <*> a8 <*> a9 <*> a10 <*> a11
是f :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> String -> String -> String -> Int
以及对应于每种类型的a1 .. a11
值
库中有一个类似函数的列表:
- 有两个参数:
public static <T1, T2, R> Single<R> zip(SingleSource<? extends T1> source1, SingleSource<? extends T2> source2,BiFunction<? super T1, ? super T2, ? extends R> zipper) {
ObjectHelper.requireNonNull(source1, "source1 is null");
ObjectHelper.requireNonNull(source2, "source2 is null");
return zipArray(Functions.toFunction(zipper), source1, source2);
}
- 有三个:
public static <T1, T2, T3, R> Single<R> zip(
SingleSource<? extends T1> source1, SingleSource<? extends T2> source2,
SingleSource<? extends T3> source3,
Function3<? super T1, ? super T2, ? super T3, ? extends R> zipper)
等等...
在所有这些情况下,都很好,因为每个参数都是类型化的。但有一个限制,直到9个单一源
在我们的项目中,我们需要更多的源代码,因为我们有很多服务需要异步(在我们的例子中是11个参数)。
但问题是参数失去了它们的强类型,更糟糕的是,其中一些可能是Nullable
例如,我们希望解决以下使用情形:
//Given
val bothSubscribed = CountDownLatch(2) // Change this value to 0 to run the test faster
val subscribeThreadsStillRunning = CountDownLatch(1) // Change this value to 0 to run the test faster
val service = { s1: String,
s2: Int,
s3: String?,
s4: Int,
s5: String,
s6: String,
s7: String,
s8: String,
s9: String,
s10: String?,
s11: String ->
val result =
listOf(s1, "$s2", s3 ?: "none", "$s4", s5, s6, s7, s8, s9, s10 ?: "none", s11).joinToString(separator = ";")
Single.just("Values:$result")
}
val createSingle = { value: String ->
Observable
.create<String> { emitter ->
println("Parallel subscribe $value on ${Thread.currentThread().name}")
bothSubscribed.countDown()
subscribeThreadsStillRunning.await(20, TimeUnit.SECONDS)
emitter.onNext(value)
emitter.onComplete()
}
.singleOrError()
.subscribeOn(io())
}
val s1 = createSingle("v1")
val s2 = Single.just(2)
val s3 = null
val s4 = Single.just(4)
val s5 = createSingle("v5")
val s6 = createSingle("v6")
val s7 = createSingle("v7")
val s8 = createSingle("v8")
val s9 = createSingle("v9")
val s10 = null
val s11 = createSingle("v11")
//When
val result = Single.zipArray(
listOf(
s1,
s2,
s3,
s4,
s5,
s6,
s7,
s8,
s9,
s10,
s11
)
) { arrayResult ->
service(
arrayResult[0] as String,
arrayResult[1] as String,
arrayResult[2] as String?,
arrayResult[3] as String,
arrayResult[4] as String,
arrayResult[5] as String,
arrayResult[6] as String,
arrayResult[7] as String,
arrayResult[8] as String,
arrayResult[9] as String?,
arrayResult[10] as String
)
}
//Then
result
.test()
.awaitDone(50, TimeUnit.SECONDS)
.assertSubscribed()
.assertValues("Values:v1;2;none;4;v5;v6;v7;v8;v9;none;v11")
如您所见,如果我这样做,可能会出现问题,例如:
arrayResult[0] as String,
arrayResult[1] as Int,
arrayResult[2] as String?,
arrayResult[3] as Int,
arrayResult[4] as String,
arrayResult[5] as String,
arrayResult[6] as String,
arrayResult[7] as String,
arrayResult[8] as String,
arrayResult[9] as String?,
arrayResult[10] as String
2条答案
按热度按时间6psbrbz91#
一个有11个参数的函数就是一个不干净代码的好例子。相反,你应该考虑建立一个模型来满足你的需要。像这样,你也可以为每个参数提供有意义的名称。
有了这个模型,您只需在每个源代码上使用
zipWith()
操作符。如果您考虑将可空性抽象为
Maybe
,则可以简单地定义一个扩展函数,接收带数据或不带数据的Maybe
,并适当地Map它。ogq8wdun2#
我已经通过以下方式实现了这一目标:
1.Kotlin扩张函数
1.部分应用(Kotlin也允许)
1.函子和应用函子概念(单个和可观察类是应用函子)
1.把它们混合在一起:
首先是
zipOver
函数,对于不可为空的值:然后,
zipOverNullable
表示可空值:我对
curried()
函数使用了org.funktionale.currying把这两个结合起来,你可以写:
然后它打印如下内容:
现在,如果我这样做:
它将在编译时中断