分类:Uncategorized

关于RIZAP的一切

关于RIZAP的一切

2018年做的不一定是最有价值,但一定最成功的事,就是参加了RIZAP。

我参加了三个月的课程,体脂率从26%减到18%,体重从79kg减到69kg,算是达到了预期目标。

什么是RIZAP?

RIZAP是日本的一家网红私人健身室,广告铺天盖地,广告都是一个风格:名人的Before&After。随着魔性的BGM,拖着肥肉的大叔大姐转进去,健美的身材转出来。100%迎合了现代消费者减肥的诉求。

RIZAP不仅在首都圈有大量的门店,在上海、台北、香港等城市都有分店。

为什么去RIZAP?

工作后吃得好了运动得少了自然就胖了,特别是近年升职后责任重了,睡得也不好,这些都是肥胖的原因。虽然BMI还没到肥胖线,但是很明显小腹突起,双下巴也出来了。身体检查有轻微的高血压高血脂迹象,睡眠鼾声也大了,减肥势在必行。

为什么选择RIZAP?

  • RIZAP是宣称肯定有效果,不满意可以退钱,成功例子也多。我以前也上过健身房,但是没什么成果,基本乱练。去RIZAP有点像手游的课金和USJ的Express票,社会人经不起折腾,用钱换时间。
  • 换了工作,工资有大幅提升,比起成本更注重效果。
  • RIZAP门店多,不会有预约不上的问题。RIZAP虽然贵,其他私教也不便宜。
  • RIZAP的服务质量是真的好。
  • 好奇。RIZAP在EdTech领域算是一个网红,非常好奇他们是怎样打造这个服务的。

RIZAP的缺点

就一个字:!真的是非常贵!

RIZAP是真的贵,入会费5万日元(介绍的话可以免入会费,我是推友介绍的),教学费每月15万(8节课)左右,而要是买他们家的补剂的话,就更贵,比如说30包的蛋白粉就要约3万日元。我自己是买了每月7万日元的全家桶补剂,加起来三个月约70万左右。要知道我在日本读两年master学位的学费加起来也才70万。

RIZAP的课程

课程长度

进去RIZAP之前,会有一次咨询。主要就是明确想要什么样的身体,然后RIZAP给出他们的方案。我自己的目标很明确,就是减脂,把三高的潜在风险减掉,回到健康的身体。

RIZAP风格的广告有一个误导人的地方是,那些从肥仔肥女变成型男俏女的明星参加的都是起码八个月左右的课程,他们不止减脂还有一定的增肌才有这样的身材。一般人参加的两三个月的课程其实只够减脂。我选择的也是三个月,毕竟贵啊。

饮食限制

RIZAP有一个著名的地方就是“糖质制限”,也就是低碳水化合物饮食。每天摄取的碳水化合物标准是不超过50g,其实有点接近生酮了。然而生酮虽然很有效,但其实有一定的危险性的,健身圈一般不建议超过三个月的生酮。我自己课程完了以后就把生酮换成一般的低碳水了。

RIZAP入会时会发一个手册,告诉你什么可以吃什么不可以吃,大体上跟生酮差不多。RIZAP还有个app,不太好用的app,用来跟踪会员的所有饮食。功能上类似myfitnesspal,但不如myfitnesspal好使,至少不能扫条形码,我自己是记了一个月习惯以后就只发照片了。教练会每两三天评价一次,给点饮食的建议。这些建议对于进入生酮时帮助很大,但到后期习惯就比较鸡肋。因为我每天吃的东西都自己做都差不多,怎么看都不会超糖。减脂主要靠的还是热量赤字,吃得多就是只吃蛋白质也没用。

其实RIZAP也不只限糖,对于增肌的人就变成限脂肪了。不过体脂肪率低到可以增肌的人估计都不会去RIZAP就是了。

课程内容

一周两节课,基本都是大肌群胸背腿肩,一天胸肩一天背腿,然后结束前做卷腹。教练说课程因目的是差很远的,比如男女之间就有大差,毕竟很多女生不想要胸肌。

项目基本是自由重量,器械偶尔辅助。大重量和多组数轮流做。

RIZAP的教练水平真不是盖的,至少我见到的每个男教练都有很明显的训练痕迹,据说他们每个工作日都会互练一个小时以上。我的教练宫坂也是,他还参加地方健美大赛。每个动作做示范时他都让我摸一下他的肌肉理解一下肌肉的感受度,让我这种健身小白好生羡慕。

其实两节课训练量还是不足的,我后期平台期基本都会在家里另外练两天。虽然RIZAP也有器械,预约制免费用,但还是家里舒服。其实有哑铃胸背腿肩都可以练了,就是不敢上大重量就是。家里练的项目问教练都会教,跟教练学习还是获益良多的。

收益

  • 体脂率和体重都达到了预期目标,外表也回到毕业时水平甚至更好。
  • 健身算是入门了,现在看健身方面的资料看得进去了,去自由重量区也敢操杠铃了。
  • 养成了健身和良好的饮食习惯,减少了未来的健身风险。

下一步

  • 继续刷体脂,目标是这个2019第一季度刷进13%。
  • 刷好了就增肌。
  • 把减肥心得总结一下。

2018订阅的服务

  • Grammarly
    • 英文语法检查SaaS
    • 打折后$83.97/year。标准价格非常贵,年末的黑五销售比较给力。注册后一直不升级的话自动化销售会给你coupon,相对来说比较便宜。
    • 要是公司给钱买的话就续下去。否则的话再等减价。
  • スタディサプリEnglish
    • 英文在线学习,主要是托业。
    • 16,680円/6 months
    • 内容质量非常高。不过考完Toeic就不续了。
  • dマガジン
    • 包月杂志
    • 432円/month
    • 性价比非常高,有我每个月都要读的《東洋経済》《Tarzan》等杂志。肯定续。
  • MoneyForward Me
    • 家計管理SaaS
    • 480円/month
    • 比较实用,能跟非常多的服务连接数据。可以分组,夫妇的钱都能管理。续。
  • Amazon Music Unlimited Family Plan
    • 包月听歌
    • 1480円/month
    • 本来是用的个人版,因为夫人买了个Bose就升级了。不贵,应该续。
  • Amazon Prime Family Plan
    • 不用说,肯定续
  • Netflix 4K
    • 1800円/month
    • 买了新4K电视于是升的4K,无特别感觉。续是打算续的,打算降回去。本来Netflix看的也不算多。
  • Cocoro Video
    • 夏普电视专有的VOD影视
    • 540円/month
    • 每个月给540积分,一般够看一部电影。特点是高清,而且上线比其它厂早一个月左右。观望。
  • Times Car Plus
    • 租车服务
    • 1030円/month
    • 跟CocoroVideo有点像,也是OnDemand服务的Subscription版。每个月交会费返还1000点。主要用来去Costco。续。
  • Costco
    • 会员制超市
    • 4,400円(税抜)/year
    • 便宜,而且搬家后更方便去了。续。
  • MyFitnessPal
    • 健身系SaaS
    • ¥6,000/year
    • 用来记录每天饮食的营养,年末刚开通,用起来还行。观望。

Programming in Scala [4]

读书笔记(4)

Chapter 4 Classes and Objects

变量作用域

  • 跟Java一样,Scala也是用花括号{}定义新的变量作用域(scope)。要在scope之外引用变量,只能通过继承/import/成员变量。
  • 一旦定义了变量,不能在同一域里用同一名字定义变量
val a = 1
val a = 2  // 编译错误
println(a)
val a = 1;  // 这里";"是必须的
{
  val a = 2  // 编译通过
  a
}
println(a) // 输出1, 因为花括号内的a跟外面的a无关。
  • 第二段代码在Scala能编译通过,然而在Java里是不允许括号内部的变量与外部的变量同名。在Scala里此括号外部的同名变量在括号内部是不可见的。
  • Scala这么做是为了创造更方便的交互环境。
  • 在interpreter里,Scala可以重复定义一个变量。
scala> val a = 1
a: Int = 1
scala> val a = 2
a: Int = 2
scala> println(a)
2
  • interpreter可以这样做的原因是它会自动为每一段语句创建一个嵌套的花括号。上面的代码相当于
val a = 1;
{
  val a = 2;
  {
    println(a)
  }
}

分号推定

  • Scala里句末的分号通常是可省略的。
  • 只有在你要在一行里写多句语句时,分号才是必要的。
  • 这个特性有时会产生有违你本意的结果,比如
x
+ y

Scala 会把这段分成两行:x+y。要两行算x+y,可用

(x
+ y)

x +
y +
z

这样的写法。

如果下面三个条件满足一个或以上,该行就不会被判断为已完结

  • 该行用.infix-operator(后述)等不合法的语法结尾。
  • 次行的开头的词不能用作开头。
  • 该行的括号()[]没完结。因为它们内部不允许多行。

单例对象

又是单例对象。

  • 单例对象与其伴生类可以互相访问私有成员。
  • 对Java程序员来说,理解单例对象最好的方法就是:它是Java里所有静态方法的集合体。用法跟Java里的也差不多。
  • 跟Java最大的不同是,单例对象不能用new初始化,所以它们的构造函数是不能带参数的。
  • 单例对象的实现方式是通过静态变量,实际上它们的初始化方式是跟Java的静态成员差不多的。单例对象只会在第一次被访问时初始化。
  • 单例对象适合用来放置工具函数。(比如之前关于List的那章,就用List.apply这个工厂函数生成新的不可修改对象)
  • 没有伴生类的standalone object还可以用来定义一个Scala程序的入口,书里的4.9小节有介绍,这里省略。

Chapter 5 基本类型和操作符

  • 虽然Scala里所有值皆是对象,但为了运行效率Scala编译器实际上会把一部分值用Java的原始类型表达。
  • Scala的基本类型:ByteShortIntLongCharStringFloatDoubleBoolean。(本来想找官方文档的,没有。书里的Table 5.1)
  • 除了Stringjava.lang包里,其他的基本类型都是scala包里。比如Int的全名是scala.Int
  • scalajava.lang会被自动引用到所有的Scala源文件里。你只用使用缩写,比如Int
  • 这些类型的取值范围跟Java的原始类型一致,这是为了能在转换成字节码时优化成Java的原始类型。
  • 这些基本类型都有全小写的别名,跟Java的原始类型一样,但请跟随社区的选择,别使用。(我用2.11.7试了下,已经不能使用了)。

Literals(符码)

  • Literal指的是我们在代码里对常量的在文面上的表达方式。
  • Scala的literals跟Java的几乎一样。
    • 整数(与Java一样)
    • 浮点小数(与Java一样)
    • 字符(与Java一样)
    • 字符串(与Java一样,唯一的不同,就是Scala支持多行字符串符码),比如:
println("""Welcome to Ultamix 3000.
             Type "HELP" for help.""")  // 没有对齐
             
println("""|Welcome to Ultamix 3000.
           |Type "HELP" for help.""".stripMargin) // 通过`stripMargin`方法对齐

用的是""",跟python与ruby类似。

操作符是方法

  • 反复说了。Java里的操作符是语法,Scala里的操作符是方法。既然是方法,自然也可重载。
  • 当不使用.()来调用一个方法时,使用的是下面三个操作符记法的其中之一:
    • prefix(前缀):操作符放于值之前,比如-7里的-
    • postfix(后缀):操作符放于值之后,比如7 toLong里的to Long
    • infix(中缀):操作符放于值之中,比如7 + 2里的+
  • 操作符与值之间的空格不是必须的,比如1+21 + 2(1).+(2)1.+(2)是完全一样的。(当然了,这只在不存在歧义时才成立)。
  • 操作符记法可适用于任何方法,比如String的indexOf,如str indexOf 'o'
  • 当你使用中缀记法来调用一个多于一个参数的方法时,要用括号,如str indexOf ('o',5),相当于str.indexOf('o', 5)
  • 与中缀记法不一样,前缀与后缀记法是unary的,也就是一元操作符。
  • 前缀记法是调用特定方法的简略写法,比如-2.0里的-,实际调用的是一个带unary_前缀的方法:unary_-。Scala会把-2.0自动转换成(2.0).unary_-
  • 只有+,-,!,~四个特殊字符能成为前缀方法。像unary_*一类的方法是不能用前缀记法调用的(但可正常调用)。
  • 后缀就比较简单了,没有任何参数的方法都可以用后缀记法调用。

Scala里的操作符

虽然本质不一样,用起来跟Java大同小异,只写比较关心的部分。

  • Scala里的浮点小数求余用的不是IEEE 754标准,要用专用的IEEEremainder方法。(Java好像也是一样的。)
  • Scala里的逻辑与和逻辑或跟Java一样,是可以短路的。由于Scala的逻辑与和逻辑或实际上是方法,所以其实Scala是可以做到选择性地不计算参数里的函数的。这是通过Scala的延迟计算特性来实现的,具体后述。

对象比较(Object equality)

  • Scala里的对象比较可以比较所有对象,不仅是基本类型。如:
scala> 1 == 2
res24: Boolean = false
scala> 1 != 2
res25: Boolean = true
scala> 2 == 2
res26: Boolean = true

scala> List(1,2,3) == List(1,2,3)
res27: Boolean = true
scala> List(1,2,3) == List(4,5,6)
res28: Boolean = false

scala> 1 == 1.0
res29: Boolean = true
scala> List(1,2,3) == "hello"
res30: Boolean = false

scala> List(1,2,3) == null
res31: Boolean = false
scala> null == List(1,2,3)
res32: Boolean = false
  • 在Java里,对于原始类型,==比较值;对于引用型变量,==比较的是两者是否引用JVM的heap里的相同对象。
  • 在Scala里,==实际是调用了equals,只要实现了基于内容比较的equals,就能比较两者内容是否一致。
  • Scala里有Java式的比较函数的实现eqne,后述。

操作符优先级(operator precedence)

  • Scala里没有操作符优先级,但有方法优先级。
  • 方法的优先级是通过方法名的首字符判断的。比如说,*开头的方法比+开头的方法优先,所以2 + 2 * 7 = 2 + (2 * 7)
  • 具体优先级如下:
  • 当优先级一样时,Scala通过方法名的未字符判断其关联性(associativity,就是判断操作数与其左侧还是右侧的操作数组合)。一般的方法是从左到右结合,当方法名以:结尾时,从右到左结合(前面关于String的一章有提过)。所以,a ::: b ::: c相当于a ::: (b ::: c),而a * b * c相当于a * (b * c)
  • 千万别为了炫耀自己对于操作符的理解而省略括号!!!你应该默认所有的程序员只知道*,/,%优先于+,-。除此之外的所有运算符都应该加括号!!!

关于这一点,我个人深有同感。我自己在给后辈做code review时,有违这个原则的,都打回去要求写括号。Scala作为一门为了简洁可以去掉句末;的语言,作者却要求明确写出括号注明优先级,可以看出这个括号是不可少的。究其原因,除了作者所述的原因外,我觉得还有一点:不同的语言的操作符优先级不一定一样。

比如说,PHP里,赋值运算符比比较运算符优先级高,而在JavaScript里,比较运算符比赋值运算符优先级高。在某些脚本语言里,逻辑与和逻辑或是同级的,如bash。更极端的甚至有语言是没有运算符优先级的,比如LISP那堆。要填上不同背景的工程师之间的鸿沟,括号是最优雅简单的选择。如果你觉得括号省去也没啥问题,很可能是你学的语言还不够多。

未完待续。

Programming in Scala [2]

读书笔记(2)

Chapter 3 Next Steps in Scala

带类型数组

Scala里的用参数创建实例(parameterize)的方法:

val greetStrings = new Array[String](3)
greetStrings(0) = "Hello"
greetStrings(1) = ","
greetStrings(2) = "world! \n"

for (i <- 0 to 2)
  print(greetStrings(i))
  • 这里greetStrings的类型是Array[String]。(类似Java5引入的泛型。)
  • 使用val后,不能再修改引用,但引用的对象可以修改。
  • 跟Java不同,泛型使用方括号[],下标引用使用圆括号()
  • 0 to 2里的to是方法名,相当于(0).to(2),它返回一个Scala的包含0,1,2iterator。Scala里的+,-,*,/都是方法名。
  • 在Scala里,Array也是类。当在实例后面使用(),Scala会调用一个叫apply的方法。greetStrings(i)相当于greetStrings.apply(i)。不止Array,任何实例后面接()都会调用对应的apply
  • 类似地,greetStrings(0) = "Hello"相当于greetStrings.update(0, "Hello")
  • 不像其他语言,上述的这种变换在Scala里不会明显影响性能。Scala编译器会尽量把他们优化成Java的本地数组或者原始类型(primitive type,像int一类)。

关于List和Tuple

  • 如上例所示,Scala的Array是同一类型的值的可修改的序列。像上述的Array[String],虽然长度不可修改,但内容可修改。所以Array是可修改的。(为避免混乱,本笔记系列会把所有mutable都译成可修改,反之immutable都译成不可修改)
  • 比Array更适合函数语言的,是List,它不可修改。它也是同一类型的值的序列。跟Java的java.util.List不一样,Scala的List,也就是scala.List,它是总不可修改的。它是为函数风格编程设计的。

List的示例

val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour

val twoThree = List(2, 3)
val oneTwoThree = 1 :: twoThree
  • List的创建没用new,因为它调用的是List的伴生对象(companion object,后述)的apply方法。
  • 两个List相接,用:::。它用于把一个List接到另一个List的前面,也就是prepend
  • 在Scala里一般的方法是从左到右的,比如a * b相当于a.*(b)。而:结尾的方法则反之,a ::: b相当于b.:::(a),所以说是把a接于b的前面
  • :: 念“cons”。cons用来把一个元素接到一个List前面,与:::同理。
  • List是没有append的,因为它的时间复杂度是O(n)。

题外话:关于List的时间复杂度

自己总结了一下Scala的List的一些性能资料12

  • List是为后入先出(LIFO)优化的,类似Stack。如果要使用其他访问方式,别用List。
  • List只有prepend,访问链首or链尾三个操作是O(1)的,其他如随机访问,lengthappendreverse都是O(n)的。
  • Java的List的话则有两个实现ArrayListLinkedList,伪代码3如下
public ArrayList<T> {
    private Object[] array;
    private int size;
}
public LinkedList<T> {
    class Node<T> {
        T data;
        Node next;
        Node prev;
    }
    private Node<T> first;
    private Node<T> last;
    private int size;
}

可以看出来,随机访问的话,ArrayList快,增删的话,LinkedList比较好4

Scala的Tuple

  • 跟List一样,是不可修改的。
  • 跟List不同,Tuple的各个值类型是不一样的。
  • Tuple非常适合同时返回多个值。(Python等语言也可以,非常实用。Java的话只能用类似JavaBean或直接修改输入,超级恶心)
val pair = (99, "Luftballons")
println(pair._1)
println(pair._2)
  • 可以直接用()生成。Scala会自动判断类型,这里是生成了一个可容纳两个值的Tuple2[Int, String]
  • 不可以像List那样通过像pair(1)一样的下标访问的方式使用,因为Tuple各个值类型不一样。只能通过像pair._1一样访问
  • 数据序号从1开始,Tuple最多只能到Tuple22,容纳22个值。这个数字其实是任意的。

Set与Map

  • Scala里的List总是不可修改的,Array总是可修改的。然而Set与Map则同时有可修改与不可修改两套实现。
  • 无论Set或Map,它们的可修改不可修改版都是从同一个trait继承出来的两个subtrait,然后再继承成类。

这是可修改Set的例子:

import scala.collection.mutable.HashSet

val jetSet = new HashSet[String]
jetSet += "Lear"
jetSet += ("Boeing", "Airbus")
println(jetSet.contains("Cessna"))
  • HashSet要事先import。
  • ("Boeing", "Airbus"),这不是Tuple,而是相当于jetSet.+=("Boeing", "Airbus")。要传入Tuple的话,要使用jetSet += (("Boeing", "Airbus")),双圆括号。

这是不可修改Set的例子:

val movieSet = Set("Hitch", "Shrek")
println(movieSet)
  • 这里用了scala.collection.Set的伴生对象的工厂方法,这个对象是自动import的。

这是可修改的HashMap的例子:

import scala.collection.mutable.HashMap

treasureMap += (1 -> "Go to island.")
treasureMap += (2 -> "Find big X on ground.")
treasureMap += (3 -> "Dig.")
println(treasureMap(2))
  • 1 -> "Go to island."相当于(1).->("Go to island."),相当于生成一个两个元素的Tuple
val romanNumeral = Map(
    1 -> "I",
    2 -> "II",
    3 -> "III",
    4 -> "IV",
    5 -> "V" )
println(romanNumeral(4))
  • 跟不可修改的Set差不多,也是工厂方法。这个工厂方法就是Map(...),也就是Map.apply(...)

未完待续。

  1. http://www.scala-lang.org/api/2.11.7/index.html#scala.collection.immutable.List 
  2. http://docs.scala-lang.org/overviews/collections/performance-characteristics.html 
  3. http://stackoverflow.com/questions/10656471/performance-differences-between-arraylist-and-linkedlist 
  4. https://docs.oracle.com/javase/8/docs/api/java/util/List.html