AS3:创建一个接受 Array 和 Vector 作为参数的函数
AS3: Create a function that accepts both Array and Vector as an argument
我正在尝试创建一个适用于 Flash 中任何类似数组的对象的函数,但我真的很难找到一种方法让编译器知道我在做什么。我需要在参数上使用像 indexOf 这样的函数,但除非它被强制转换为正确的数据类型,否则编译器不知道该方法可用。这令人沮丧,因为 Vector 和 Array 共享几乎相同的接口,但没有一个接口来反映这一点!
目前我得到了这个:
private function deleteFirst(tV:* , tVal:*):void {
trace(tV)
var tIndex:int
if (tV is Array) {
var tArray:Array = tV as Array
tIndex = tArray.indexOf(tVal)
if (tIndex >= 0) tArray.splice(tIndex, 1)
} else if (tV is Vector.<*>) {
var tVObj:Vector.<*> = tV as Vector.<*>
tIndex = tVObj.indexOf(tVal)
if (tIndex >= 0) tVObj.splice(tIndex, 1)
} else if (tV is Vector.<Number>) {
var tVNum:Vector.<Number> = tV as Vector.<Number>
tIndex = tVNum.indexOf(tVal)
if (tIndex >= 0) tVNum.splice(tIndex, 1)
} else if (tV is Vector.<int>) {
var tVInt:Vector.<int> = tV as Vector.<int>
tIndex = tVInt.indexOf(tVal)
if (tIndex >= 0) tVInt.splice(tIndex, 1)
} else if (tV is Vector.<uint>) {
var tVUInt:Vector.<uint> = tV as Vector.<uint>
tIndex = tVUInt.indexOf(tVal)
if (tIndex >= 0) tVUInt.splice(tIndex, 1)
}
trace(tV)
}
有点效果,但不够优雅!我想知道我是否缺少一个技巧。理想情况下,我会通过扩展基础 class 来做到这一点,但我认为 Vector 不可能做到这一点。
谢谢
这绝对是AS3的短板,我觉得没有什么优雅的解决办法。
但是,您可以进行一种代码简化:
由于 indexOf()
和 splice()
的语法对于数组和向量都是相同的,因此您不需要那么大的 if/else 阶梯来转换每种类型。您可以简单地在对象上调用 indexOf()
和 splice()
而无需任何强制转换。当然,您不会在 IDE 中获得任何代码提示,但它的工作方式与您目前拥有的一样。示例:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array || arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var index:int = arrayOrVector.indexOf(searchValue)
if (index >= 0)
arrayOrVector.splice(index, 1)
}else
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
return arrayOrVector;
}
你甚至可以跳过整个 if/else 类型检查,它仍然可以工作,它只会让代码更混乱,如果你用参数调用函数,你会得到一个稍微更混乱的错误除了数组或向量(如 "indexOf not found on type Sprite" 如果你不小心传递了一个 sprite 对象)。
另外值得一提的是,虽然这对数字基类型向量没有帮助,但对于其他向量,您可以某种使用Vector.<*>
作为通用矢量参考。您可以使用带通配符 (Vector.<*>(myVector)
) 的 Vector global function 分配引用,它将 return 引用原始向量而不是像通常那样创建新副本。如果您不介意 return 复制基于数字的类型向量而不是总是修改原始向量,您仍然可以利用它来简化代码:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array) {
var array:Array = arrayOrVector;
var index:int = array.indexOf(searchValue)
if (index >= 0)
array.splice(index, 1)
return array;
}else if(arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var vector:Vector.<*> = Vector.<*>(arrayOrVector);
index = vector.indexOf(searchValue);
if (index >= 0)
vector.splice(index, 1);
return vector;
}
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
}
我会非常小心地混合和匹配向量和数组。它们最大的区别就是Arrays是稀疏的,而Vector是稠密的。
就是说,这是您非常紧凑的通用删除函数,可用于任何具有 indexOf 和拼接的 "set" class...
function deleteFirst( set:Object, elem:Object ) : Boolean
{
if ( ("indexOf" in set) && ("splice" in set) )
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
}
return false;
}
您可以使用此代码测试代码
var arr:Array = [ 1, 2, 3, 4, 5 ];
var vec:Vector.<int> = new Vector.<int>();
vec.push( 1, 2, 3, 4, 5 );
deleteFirst( arr, 2 ); // will remove 2
deleteFirst( vec, 3 ); // will remove 3
deleteFirst( "aaa4", "4" ); // nothing, cuz String doesn't have splice
trace( arr );
trace( vec );
更新 - 仅针对@Arron,我进行了以下更改。请注意,获得异常是好的。它们内容丰富,有助于揭示代码路径的问题。
function deleteFirst( set:Object, elem:Object ) : Boolean
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
return false;
}
到了!现在更简单了。你得到一个异常,告诉你哪里出了问题!
我正在尝试创建一个适用于 Flash 中任何类似数组的对象的函数,但我真的很难找到一种方法让编译器知道我在做什么。我需要在参数上使用像 indexOf 这样的函数,但除非它被强制转换为正确的数据类型,否则编译器不知道该方法可用。这令人沮丧,因为 Vector 和 Array 共享几乎相同的接口,但没有一个接口来反映这一点!
目前我得到了这个:
private function deleteFirst(tV:* , tVal:*):void {
trace(tV)
var tIndex:int
if (tV is Array) {
var tArray:Array = tV as Array
tIndex = tArray.indexOf(tVal)
if (tIndex >= 0) tArray.splice(tIndex, 1)
} else if (tV is Vector.<*>) {
var tVObj:Vector.<*> = tV as Vector.<*>
tIndex = tVObj.indexOf(tVal)
if (tIndex >= 0) tVObj.splice(tIndex, 1)
} else if (tV is Vector.<Number>) {
var tVNum:Vector.<Number> = tV as Vector.<Number>
tIndex = tVNum.indexOf(tVal)
if (tIndex >= 0) tVNum.splice(tIndex, 1)
} else if (tV is Vector.<int>) {
var tVInt:Vector.<int> = tV as Vector.<int>
tIndex = tVInt.indexOf(tVal)
if (tIndex >= 0) tVInt.splice(tIndex, 1)
} else if (tV is Vector.<uint>) {
var tVUInt:Vector.<uint> = tV as Vector.<uint>
tIndex = tVUInt.indexOf(tVal)
if (tIndex >= 0) tVUInt.splice(tIndex, 1)
}
trace(tV)
}
有点效果,但不够优雅!我想知道我是否缺少一个技巧。理想情况下,我会通过扩展基础 class 来做到这一点,但我认为 Vector 不可能做到这一点。
谢谢
这绝对是AS3的短板,我觉得没有什么优雅的解决办法。
但是,您可以进行一种代码简化:
由于 indexOf()
和 splice()
的语法对于数组和向量都是相同的,因此您不需要那么大的 if/else 阶梯来转换每种类型。您可以简单地在对象上调用 indexOf()
和 splice()
而无需任何强制转换。当然,您不会在 IDE 中获得任何代码提示,但它的工作方式与您目前拥有的一样。示例:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array || arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var index:int = arrayOrVector.indexOf(searchValue)
if (index >= 0)
arrayOrVector.splice(index, 1)
}else
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
return arrayOrVector;
}
你甚至可以跳过整个 if/else 类型检查,它仍然可以工作,它只会让代码更混乱,如果你用参数调用函数,你会得到一个稍微更混乱的错误除了数组或向量(如 "indexOf not found on type Sprite" 如果你不小心传递了一个 sprite 对象)。
另外值得一提的是,虽然这对数字基类型向量没有帮助,但对于其他向量,您可以某种使用Vector.<*>
作为通用矢量参考。您可以使用带通配符 (Vector.<*>(myVector)
) 的 Vector global function 分配引用,它将 return 引用原始向量而不是像通常那样创建新副本。如果您不介意 return 复制基于数字的类型向量而不是总是修改原始向量,您仍然可以利用它来简化代码:
function deleteFirst(arrayOrVector:* , searchValue:*):* {
if (arrayOrVector is Array) {
var array:Array = arrayOrVector;
var index:int = array.indexOf(searchValue)
if (index >= 0)
array.splice(index, 1)
return array;
}else if(arrayOrVector is Vector.<*> || arrayOrVector is Vector.<Number> || arrayOrVector is Vector.<int> || arrayOrVector is Vector.<uint>) {
var vector:Vector.<*> = Vector.<*>(arrayOrVector);
index = vector.indexOf(searchValue);
if (index >= 0)
vector.splice(index, 1);
return vector;
}
throw new ArgumentError("Argument 'arrayOrVector' must be an array or a vector, but was type " + getQualifiedClassName(arrayOrVector));
}
我会非常小心地混合和匹配向量和数组。它们最大的区别就是Arrays是稀疏的,而Vector是稠密的。
就是说,这是您非常紧凑的通用删除函数,可用于任何具有 indexOf 和拼接的 "set" class...
function deleteFirst( set:Object, elem:Object ) : Boolean
{
if ( ("indexOf" in set) && ("splice" in set) )
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
}
return false;
}
您可以使用此代码测试代码
var arr:Array = [ 1, 2, 3, 4, 5 ];
var vec:Vector.<int> = new Vector.<int>();
vec.push( 1, 2, 3, 4, 5 );
deleteFirst( arr, 2 ); // will remove 2
deleteFirst( vec, 3 ); // will remove 3
deleteFirst( "aaa4", "4" ); // nothing, cuz String doesn't have splice
trace( arr );
trace( vec );
更新 - 仅针对@Arron,我进行了以下更改。请注意,获得异常是好的。它们内容丰富,有助于揭示代码路径的问题。
function deleteFirst( set:Object, elem:Object ) : Boolean
{
var idx:int = set.indexOf( elem );
if ( idx >= 0 )
{
set.splice( idx, 1 );
return true;
}
return false;
}
到了!现在更简单了。你得到一个异常,告诉你哪里出了问题!