假设我已经定义了这样的协议:
protocol EuclideanPoint {
func distance(other: Self) -> Double
func dimension() -> UInt
}
现在,我想扩展[Float]
并[Double]
采用该协议。
但是下面的代码:
extension [Float]: EuclideanPoint {
func distance(other: [Float]) {
return Double(zip(self, other).map{a, b in pow(a-b,2)}.reduce(0, combine: +))
}
func dimension() {
return UInt(self.count)
}
}
由于错误而无效
错误:必须在非专用泛型类型“ Array”上声明受约束的扩展,并使用“ where”子句指定约束
我发现类似的问题,但建议的解决方案是使用extension CollectionType where Generator.Element == S { ... }
,但在这种情况下它会导致错误:
错误:协议“ CollectionType”只能用作一般约束,因为它具有“自我”或相关类型要求
有什么解决办法吗?
编辑:
使用建议的解决方案:
protocol DoubleConvertibleType {
var doubleValue: Double { get }
}
extension Double : DoubleConvertibleType { var doubleValue: Double { return self } }
extension Float : DoubleConvertibleType { var doubleValue: Double { return Double(self) } }
extension CGFloat: DoubleConvertibleType { var doubleValue: Double { return Double(self) } }
extension Array where Element : DoubleConvertibleType {
func distance(other: Array) -> Double {
return Double(zip(self, other).map{ pow($0.0.doubleValue - $0.1.doubleValue, 2) }.reduce(0, combine: +))
}
func dimension() -> UInt {
return UInt(self.count)
}
}
给出[Double]
与[Float]
该.distance()
和.dimension()
方法。但是[Double]
或[Float]
不能代替符合EuclideanPoint协议所需的内容,从而产生错误:
错误:类型“ [Double]”不符合协议“ EuclideanPoint”
已编辑
以下解决方案在某种程度上是通用的,符合protocol EuclidianPoint
,并且基于两个假设:
我们可以distance
在EuclideanPoint
协议中为方法的蓝图包括通用类型约束,并且Self
我们将使用通用([T]
)代替参数类型是。我们将然而,探明(在编译时间)[T]
是相同类型的Self
(和这里,Self
的[Double]
,[Float]
或[Int]
类型),并 查明[T]符合协议EuclidianPoint
。
那你真行,我们离开函数式编程技术,如.map
和.reduce
出这个特定的应用程序,而只注重敷脸 “采用欧几里德协议通用阵列” 。这些.map
,.reduce
等在斯威夫特的壮举确实是整洁和有用的,但在许多应用程序背后的引擎盖for循环只是包装,这样你就不会失去对在手动势在必行的风格做事任何性能。实际上,.reduce
由于重复执行array-copy-assignments减少数组的同时,已知执行非可选的操作(我在这里不再赘述…)。无论如何,也许您可以利用我的示例并将其调整回更多的功能范例。
我们从一个自定义类型协议开始,该协议MyTypes
将充当我们要包含在泛型中的类型的接口。我们还html" target="_blank">添加了稍微更新的EuiclidianPoint
协议,在该协议中,我们将协议用作对功能蓝图中使用MyTypes
的泛型的类型约束。T``distance (...)
/* Used as type constraint for Generator.Element */
protocol MyTypes {
func -(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : MyTypes { }
extension Double : MyTypes { }
extension Float : MyTypes { }
/* Extend with the types you wish to be covered by the generic ... */
/* Used as extension to Array : blueprints for extension method
to Array where Generator.Element are constrainted to MyTypes */
protocol EuclideanPoint {
func distance<T: MyTypes> (other: [T]) -> Double?
func dimension() -> UInt
}
请注意,我已将Double
返回值distance
更改为可选值;您可以按照自己的意愿进行处理,但是如果self
and
other
数组的长度不同,或者类型Self
和类型[T]
不同,则需要显示不符合项-我将nil
在此使用。
现在,我们可以Array
通过EuclidianPoint
协议来实现我们的扩展:
/* Array extension by EuclideanPoint protocol */
extension Array : EuclideanPoint {
func distance<T: MyTypes> (other: [T]) -> Double? {
/* [T] is Self? proceed, otherwise return nil */
if let a = self.first {
if a is T && self.count == other.count {
var mySum: Double = 0.0
for (i, sElement) in self.enumerate() {
mySum += pow(((sElement as! T) - other[i]) as! Double, 2)
}
return sqrt(mySum)
}
}
return nil
}
func dimension() -> UInt {
return UInt(self.count)
}
}
请注意,在distance
函数的内部if子句中,我们使用了显式的down强制转换为T
,但是由于我们断言的元素Self
是type
T
,所以可以。
无论如何,我们已经完成了,我们可以测试我们的“通用”数组扩展,我们现在注意到这些扩展也符合您的协议EuclidianPoint
。
/* Tests and Examples */
let arr1d : [Double] = [3.0, 4.0, 0.0]
let arr2d : [Double] = [-3.0, -4.0, 0.0]
let arr3d : [Double] = [-3.0, -4.0]
let arr1f : [Float] = [-3.0, -4.0, 0.0]
let arr1i = [1, 2, 3]
let _a = arr1d.dimension() // 3, OK
let _b = arr1d.distance(arr2d) // 10, OK (A->B dist)
let _c = arr1d.distance(arr1f) // nil (Incomp. types)
let _d = arr1d.distance(arr3d) // nil (Incomp. sizes)
let _e = arr1i.distance(arr1d) // nil (Incomp. types)
/* for use in function calls: generic array parameters constrained to
those that conform to protocol 'EuclidianPoint', as requested */
func bar<T: MyTypes, U: protocol<EuclideanPoint, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Double? {
// ...
return arr1.distance(Array(arr2))
/* We'll need to explicitly tell the distance function
here that we're sending an array, by initializing an
array using the Array(..) initializer */
}
let myDist = bar(arr1d, arr2d) // 10, OK
好!
我的第一个答案中还剩下一条笔记:
实际上刚刚在这里要求将泛型类型Array扩展为协议:
共识是您 不能以 您期望的“简洁快速”的方式将 数组通用扩展到协议
。但是,有一些变通办法可以模仿这种行为,其中一个就是我上面使用的变通办法。如果您对另一种方法感兴趣,建议您研究此线程。
问题内容: public class MyGeneric {} 据我所知,以上示例中的两个子类均有效。我想知道Java如何知道何时在实例化子类时定义超类中给定的类型,以及何时将它们定义为实际的类名(即,它如何知道T,E不是类名)? 旁注,是否允许(即使不常见)对通用类型使用多个字母?如果(由于某些严重的计划错误)类型与现有类冲突,该怎么办? 那会发生什么呢? 编辑:感谢您的及时答复。为了回答我的第
扩展说明 RPC 协议扩展,封装远程调用细节。 契约: 当用户调用 refer() 所返回的 Invoker 对象的 invoke() 方法时,协议需相应执行同 URL 远端 export() 传入的 Invoker 对象的 invoke() 方法。 其中,refer() 返回的 Invoker 由协议实现,协议通常需要在此 Invoker 中发送远程请求,export() 传入的 Invoker
协议和扩展 你可以扩展一个已经存在的类型来采纳和遵循一个新协议, 就算是你无法访问现有类型的源代码也行. 扩展可以添加新的属性、方法和下标到已经存在的类型, 并且因此允许你添加协议需要的任何需要. protocol TextRepresentable { var textualDescription: String { get } } // 此处并无Dice这个类, 以及其sides属性
问题内容: 我知道您不能动态扩展普通数组,但这是一种有效的方法吗? 我知道比尝试使用普通数组更好的方法,但是我想首先使用普通数组来解决这个问题。 我的愿望是,它从0 + 1(so 1)开始,在被称为new时,它的大小与相同,然后保持不变,同时再次声明,然后将其复制回新的大小。这对我来说很有意义,但我总是会遇到异常情况? 问题答案: 该方法不会更改OrigArray的值;它所做的只是在其中存储一个克
Array.from() Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。 下面是一个类似数组的对象,Array.from将它转为真正的数组。 let arrayLike = { '0': 'a', '1': 'b', '2': 'c',
据我所知,协议缓冲区主要用于控制服务器和客户端代码的项目。我的一般问题是——协议缓冲区能否用于将二进制消息序列化/反序列化到使用现有协议的服务器?所以,我的问题: > 如果协议缓冲区不支持本机微调现有协议的序列化/反序列化方式,那么可以通过扩展添加该功能吗?是否可以以某种方式添加序列化/反序列化方法可以识别的关键字?也许这可以通过扩展或修改protobuf csharp port或protobuf