Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
梦境迷离
Cs Summary Reflection
提交
da97ae65
C
Cs Summary Reflection
项目概览
梦境迷离
/
Cs Summary Reflection
10 个月 前同步成功
通知
4
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Cs Summary Reflection
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
da97ae65
编写于
6月 14, 2020
作者:
梦境迷离
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Scala macro
上级
3125daaf
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
240 addition
and
1 deletion
+240
-1
docs/_posts/Scala/2020-06-14-Scala-marco介绍.md
docs/_posts/Scala/2020-06-14-Scala-marco介绍.md
+239
-0
docs/_posts/面试/2020-06-10-面试-RPC相关问题.md
docs/_posts/面试/2020-06-10-面试-RPC相关问题.md
+1
-1
未找到文件。
docs/_posts/Scala/2020-06-14-Scala-marco介绍.md
0 → 100644
浏览文件 @
da97ae65
---
title
:
macro介绍
categories
:
-
Scala
tags
:
[
Scala
]
description
:
Scala的宏编程
---
*
目录
{:toc}
# Scala 泛型
-
上界 <:
-
下界 >:
-
视界 <% 允许使用宽松的通过隐式转化的方式关联
-
边界 :
-
协变 +T
-
逆变 -T
演变的其他限定
-
<:<
-
=:=
-
<%<
对于A和B这两种类型,如果编译器可以找到A <:< B类型的隐式值,则它知道A符合B(是B的子类型)。
同样,如果编译器可以找到A =:= B类型的隐式值,那么它知道A和B的类型相同。它们在编码通用类型约束时很有用。
示例如下
```
scala> def prove[T](implicit proof: T) = true
prove: [T](implicit proof: T)Boolean
scala> prove[Null <:< String]
res0: Boolean = true
scala> prove[String <:< AnyRef]
res1: Boolean = true
scala> prove[Null <:< Long]
<console>:9: error: Cannot prove that Null <:< Long.
prove[Null <:< Long]
^
scala> prove[Long <:< AnyRef]
<console>:9: error: Cannot prove that Long <:< AnyRef.
prove[Long <:< AnyRef]
^
scala> prove[AnyRef =:= java.lang.Object]
res4: Boolean = true
scala> trait Foo { type T }
defined trait Foo
scala> val foo = new Foo { type T = Int }
foo: java.lang.Object with Foo{type T = Int} = $anon$1@258361f6
scala> prove[foo.T =:= Int]
res5: Boolean = true
scala> prove[Foo#T <:< AnyRef]
<console>:10: error: Cannot prove that Foo#T <:< AnyRef.
prove[Foo#T <:< AnyRef]
^
scala> prove[Foo#T <:< Any]
res9: Boolean = true
```
# 关于宏
-
宏是程序源代码在编译前完成的对源代码一系列操作的定义
-
宏一般用来动态生成要编译的代码
-
C 中的宏
-
C 中的宏比较简单
```
#include <stdio.h>
#define PI 3.141592653589 # FLAG 1
define int main() {
#ifdef FLAG
double v = 3 * PI * 2;
printf("%f\n",v);
#else
double v = 3 * PI * 2;
printf("%d\n",v);
#endif }
```
# Scala 宏
1.
Scala 中的宏要复杂的多,但它对生成代码的方式,提供了更大的灵活性。
2.
Scala 宏仍然是用 Scala 写的,一定程序上保证了开发体验的一致。
3.
Scala 宏总是要返回一个AST,这需要你对 Scala AST 有一定的了解。
4.
但 Quasiquotes(准引用) 可以帮你轻松生成 AST。
准引用是一种简洁的表示法,使您可以轻松地操作Scala AST 语法树。
## 关于 Context
-
Context 封装了一个编译时Universe (scala.reflect.macros.Universe)
-
Context 同时也有一个 macroApplication,它提供了一个对宏展开处完整的AST
-
类型检查,编译警告、报错等
## 黑盒和白盒
一般来讲,黑盒(blackbox.Context) 会比 白盒(whitebox.Context) 有更严格的类型检查
### 黑盒例子
黑盒宏的使用, 会有四点限制, 主要方面是
-
类型检查
-
类型推到
-
隐式推到
-
模式匹配
具体看官网
[
blackbox-whitebox
](
https://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html
)
```
scala
import
scala.reflect.macros.blackbox
object
Macros
{
def
hello
:
Unit
=
macro
helloImpl
def
helloImpl
(
c
:
blackbox.Context
)
:
c.Expr
[
Unit
]
=
{
import
c.universe._
c
.
Expr
{
Apply
(
Ident
(
TermName
(
"println"
)),
List
(
Literal
(
Constant
(
"hello!"
)))
)
}
}
}
```
### 白盒例子
```
scala
import
scala.reflect.macros.blackbox
object
Macros
{
def
hello
:
Unit
=
macro
helloImpl
def
helloImpl
(
c
:
blackbox.Context
)
:
c.Tree
=
{
import
c.universe._
//可见写起来黑盒也更方便
c
.
Expr
(
q
"""println("hello!")"""
)
}
}
```
了解了Macros的两种规范之后,我们再来看看它的两种用法,一种和C的风格很像,只是在编译期将宏展开,减少了方法调用消耗。
还有一种用法,我想大家更熟悉,就是注解,将一个宏注解标记在一个类、方法或者成员上,就可以将所见的代码,通过AST变成everything。
# 定义一个宏
如果我们要传递一个参数或者泛型呢?
```
scala
object
Macros
{
def
hello2
[
T
](
s
:
String
)
:
Unit
=
macro
hello2Impl
[
T
]
def
hello2Impl
[
T
](
c
:
blackbox.Context
)(
s
:
c.Expr
[
String
])(
tag
:
c.WeakTypeTag
[
T
])
:
c.Expr
[
Unit
]
=
{
import
c.universe._
c
.
Expr
{
Apply
(
Ident
(
TermName
(
"println"
)),
List
(
Apply
(
Select
(
Apply
(
Select
(
Literal
(
Constant
(
"hello "
)),
TermName
(
"$plus"
)
),
List
(
s
.
tree
)
),
TermName
(
"$plus"
)
),
List
(
Literal
(
Constant
(
"!"
))
)
)
)
)
}
}
}
```
和之前的不同之处,暴露的方法hello2主要在于多了参数s和泛型T,而hello2Impl实现也多了两个括号
*
(s: c.Expr[String])
*
(tag: c.WeakTypeTag[T])
## c.Expr
这是Macros的表达式包装器,里面放置着类型String,为什么不能直接传String呢?
当然是不可以了,因为宏的入参只接受Expr,调用宏传入的参数也会默认转为Expr。
这里要注意, 这个
`(s: c.Expr[String])`
的入参名必须等于
`hello2[T](s: String)`
的入参名。
## WeakTypeTag[T]
有时我们无法为泛型提供边界,就需要使用WeakTypeTag,此时无法使用TypeTag和ClassTag。但是应尽可能的提供更加具体的类型给WeakTypeTag。
像Manifests一样,TypeTags总是由编译器生成,并且可以通过三种方式获得,typeTag、classTag或weakTypeTag。
[
manifests
](
https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html
)
# 关于 Universe
-
scala.reflect.api.Universe 提供了一个用来 Scala 反射的完整的操作集合,比如查看类型的成员,或反射出子类型
-
scala.reflect.api.JavaUniverse 是一个用在 JVM 实例上的对 Scala 反射的一个实现
-
scala.reflect.macros.Universe 是在进行 Scala 宏编程时对 Scala 反射的实现
-
Universe 可以看作 Scala 反射的一个入口,主要混合了以下一些类型
-
Types 类型相关
-
Symbols 定义相关
-
Trees 抽象语法树相关
-
Names term 和 type names 相关
-
Annotations 注解相关
-
Positions 源码位置相关
-
FlagSet represent sets of flags that apply to symbols and definition trees
-
Constants 编译时常量相关
想要了解 Universe 最好是应用Scala反射接口,如使用Scala注解。
# 关于 Scala AST
编译器在编译代码前首先会把 source code 解析为编译器更容易消化的抽象语法树 (Abstract Syntax Tree AST)。
[
AST在线测试
](
https://astexplorer.net/
)
\ No newline at end of file
docs/_posts/面试/2020-06-10-面试-RPC相关问题.md
浏览文件 @
da97ae65
...
...
@@ -97,7 +97,7 @@ gRPC - 是Google开发的高性能、通用的开源RPC框架,其由Google主
*
观察者设计模式
# SaaS 和私有部署平台的 gR
pc
应用有哪些区别 ?
# SaaS 和私有部署平台的 gR
PC
应用有哪些区别 ?
*
公有云SaaS平台由提供服务的公司统一运维,环境状态或变化相对可控,网络拓扑相对稳定,请求量高,需要使用高性能高可用的架构,重要服务都需要使用集群提供多个节点多个实例,由此平台本身必定会成为分布式应用,进而需要引入服务注册和发现机制(Consul),避免单个服务或节点上的故障影响SaaS的所有用户。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录