Abstract Types VS Parameterized Types

本文深入探讨Scala中的参数化类型和抽象类型,通过实例说明这两种类型如何工作,它们之间的区别及应用场景,并解释了协变和逆变的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Parameterized types

Scala supports parameterized types, which are very similar to generics in Java. Java uses angle brackets (<…>), while Scala uses square brackets ([…]), because < and > are often used for method names.

code example

val strings: List[String] = List("one", "two", "three") 

When you’re trying to understand type signatures in Scaladocs, such as the entry for List, where you’ll see that the declaration is written as sealed abstract class List[+A].

The + in front of the A means that List[B] is a subtype of List[A] for any B that is a subtype of A. This is called covariant typing. It is a reasonably intuitive idea. If we have a function f(list: List[Any]), it makes sense that passing a List[String] to it should work fine.

If there is a in front of a type parameter, the relationship goes the other way; Foo[B] would be a supertype of Foo[A], if B is a subtype of A and the declaration is Foo[-A] (called contravariant typing).

2. Abstract Types

Scala supports another type abstraction mechanism called abstract types, which can be applied to many of the same design problems for which parameterized types are used. However, while the two mechanisms overlap, they are not redundant. Each has strengths and weaknesses for certain design problems.

These types are declared as members of other types, just like methods and fields. Here is an example that uses an abstract type in a parent class, then makes the type member concrete in child classes:

import java.io._

abstract class BulkReader {
    type In
    val source: In
    def read: String // Read source and return a String
}

class StringBulkReader(val source: String) extends BulkReader {
    type In = String
    def read: String = source
}

println(new StringBulkReader("Hello Scala!").read)

Just as for parameterized types, if we define the In type to be String, the source field must also be defined as a String.

Compare them

what’s the advantage here of using type members instead of parameterized types?

The latter are best for the case where the type parameter has no relationship with the parameterized type, like List[A] when A is Int, String, Person, etc. A type member works best when it “evolves” in parallel with the enclosing type, as in our BulkReader example, where the type member needed to match the “behaviors” expressed by the enclosing type. Sometimes this characteristic is called family polymorphism or covariant specialization. (Some confusion about it Q_Q)


Ref

《Programming Scala》

package com.lc.bailingbird.conn; import android.content.Context; import android.text.TextUtils; import android.util.Log; import com.google.gson.Gson; import com.lc.bailingbird.base.BaseApplication; import com.lc.bailingbird.util.TextUtil; import com.zcx.helper.http.AsyGet; import com.zcx.helper.http.note.HttpFinish; import com.zcx.helper.http.note.HttpServer; import org.json.JSONObject; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import okhttp3.Headers; /** * Created by Administrator on 2017/2/3. */ @HttpFinish(true) @HttpServer(Conn.SERVICE_LT) public class BaseAsyGetLT<T> extends AsyGet<T> { private Context context; public BaseAsyGetLT(BaseAsyCallBack<T> asyCallBack) { super(asyCallBack); context = asyCallBack.context; } /** * 解析响应头数据,会在parser前被调用 * * @param headers */ @Override protected void parserHeaders(Headers headers) { if (!TextUtils.isEmpty(headers.get("token"))) { Log.e("parserHeaders: ", headers.get("token")); // BaseApplication.MYMMKV.encode("token", headers.get("token")); header("token", "63633bd12e294da5b7dcf949ac526d75"); } } @Override protected T parser(JSONObject object) throws Exception { TOAST = object.optString("message"); if (object.optInt("code") == 0) { Type[] types = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments(); return new Gson().fromJson(object.toString(), types[0]); } else if (object.optInt("code") == -200 || object.optInt("code") == -201) { BaseApplication.MYMMKV.encode("token", ""); BaseApplication.MYMMKV.encode("uid", ""); } return null; } @Override public void execute(boolean isShow) { super.execute(context,isShow); } @Override public void execute() { super.execute(context); } @Override public void execute(Context context, boolean isShow, int type, Object object) { if (!TextUtil.isNull(BaseApplication.MYMMKV.decodeString("token", ""))) { header("token", BaseApplication.MYMMKV.decodeString("token", "")); } super.execute(context, isShow, type, object); } } 在这个里面怎么获取我给后台接口传的值
最新发布
07-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值