模式匹配中使用的抽象类型的类型不匹配

时间:2018-09-24 12:42:55

标签: scala generics

此代码编译错误:

<%= @owner.name.gilensize.html_safe %>

从类型检查的角度来看,实现GADT的这段代码看起来非常相似,但编译时没有错误:

def f1[T](e: T): T = e match {
  case i:Int => i
  case b:Boolean => b
}
// type mismatch;
// found   : i.type (with underlying type Int)
// required: T
// case i:Int => i ...

在两种情况下,在模式匹配表达式中,我们都知道 i b Int Boolean 。为什么在第一个示例中编译失败而在第二个示例中成功编译?

3 个答案:

答案 0 :(得分:3)

第一种情况是不正确的,因为您低估了Scala类型系统中的各种类型。如果我们在进入add_filter('woocommerce_add_cart_item_data', 'add_items_default_price_as_custom_data', 20, 3 ); function add_items_default_price_as_custom_data( $cart_item_data, $product_id, $variation_id ){ ## Your settings her below ## $product_ids = array(37); // <=== Your specific product(s) ID(s) in the array $discounted_price = 12; // <=== The specific product discounted price $product = wc_get_product($variation_id > 0 ? $variation_id : $product_id); if( array_intersect( $product_ids, array($product_id, $variation_id) ) && ! $product->is_on_sale() ){ // We set the Product discounted price $cart_item_data['pricing']['discounted'] = $discounted_price; // The WC_Product Object // Set the Product default base price as custom cart item data $cart_item_data['pricing']['active'] = $product->get_price(); } return $cart_item_data; } // Display the product original price add_filter('woocommerce_cart_item_price', 'display_cart_items_default_price', 20, 3 ); function display_cart_items_default_price( $product_price, $cart_item, $cart_item_key ){ if( isset($cart_item['pricing']['active']) && $cart_item['quantity'] > 1 ) { $product_price = wc_price( wc_get_price_to_display( $cart_item['data'], array( 'price' => $cart_item['pricing']['active'] ) ) ); } return $product_price; } // Display the product name with the a custom "discount" label add_filter( 'woocommerce_cart_item_name', 'append_custom_label_to_item_name', 20, 3 ); function append_custom_label_to_item_name( $product_name, $cart_item, $cart_item_key ){ if( isset($cart_item['pricing']['discounted']) && $cart_item['data']->get_price() != $cart_item['pricing']['discounted'] ) { $discounted_price = (float) $cart_item['pricing']['discounted']; $default_price = (float) $cart_item['pricing']['active']; $quantity = (int) $cart_item['quantity']; // Calculate new product price $new_price = ($default_price + ($discounted_price * ($quantity - 1))) / $quantity; // Get the discount percentage (if needed) $percent = 100 - ($new_price / $default_price * 100); $product_name .= ' <em>(' . __('quantity discounted', 'woocommerce') . ')</em>'; } return $product_name; } // Set the new discounted price add_action( 'woocommerce_before_calculate_totals', 'set_custom_discount_cart_item_price', 25, 1 ); function set_custom_discount_cart_item_price( $cart ) { if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return; foreach( $cart->get_cart() as $cart_item ){ // For items non on sale set a discount based on quantity if( isset($cart_item['pricing']['discounted']) && $cart_item['quantity'] > 1 ) { $discounted_price = (float) $cart_item['pricing']['discounted']; $default_price = (float) $cart_item['pricing']['active']; $quantity = (int) $cart_item['quantity']; // Calculate new product price $new_price = ($default_price + ($discounted_price * ($quantity - 1))) / $quantity; // Set cart item calculated price $cart_item['data']->set_price($new_price); } } } 分支时知道case i:IntT,或者至少是Int的超类型,那将是有道理的。但这不是必须的!例如。它可以是42.typetagged type

在第二种情况下没有这样的问题,因为从Int开始,编译器 知道IntExpr <: Expr[T]必须正好是T

答案 1 :(得分:1)

您要求函数返回类型T,然后对IntBoolean进行模式匹配。 除了函数没有证据外,IntBoolean的类型也都是T:在进行模式匹配时,you introduce the constraint表示Int <: T和{{1} }。 您可以将返回类型Boolean <: T替换为T之类的固定类型,然后返回一个String,或者引入一个满足情况StringInt的约束。 / p>

Boolean

基本上,您不能只动态返回任何类型的//this compiles def f1[T](e: T ): String = e match { case _:Int => "integer" case _:Boolean => "boolean" } //this compiles too, but will return AnyVal def f1[T >: AnyVal](e: T ): T = e match { case i:Int => i case b:Boolean => b } ,因为您需要在编译时证明您的函数进行类型检出。

示例中的另一个函数通过将类型约束封装在案例类TIntExpr <: Expr[Int]中来避免该问题(请注意,BoolExpr <: Expr[Boolean]等同于Expr[_]我上面提到的约束)。在编译时,可以在所有T中正确标识T(例如,您知道case的{​​{1}}中)

答案 2 :(得分:0)

除了@Esardes答案,它还通过定义绑定到T的类型来实现:

scala> def f1[T >: AnyVal](e: T):T = e match {
     |   case i:Int => i
     |   case b:Boolean => b
     | }
f1: [T >: AnyVal](e: T)T

scala> f1(1)
res3: AnyVal = 1

scala> f1(true)
res4: AnyVal = true